Вы можете использовать iteration_utilities.roundrobin
1
u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
l = 'abcdefghijklmnopqrstuvwxyz'
from iteration_utilities import roundrobin
''.join(roundrobin(u, l))
# returns 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
или класс ManyIterables
из того же пакета:
from iteration_utilities import ManyIterables
ManyIterables(u, l).roundrobin().as_string()
# returns 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
1 Это из сторонней библиотеки, которую я написал: iteration_utilities
.
Пока добавляемая роль является объектом ActiveRecord, то, что вы делаете:
user.roles << role
Должно автоматически дедуплицироваться для ассоциаций : has_many
.
Для has_many: через
попробуйте:
class User
has_many :roles, :through => :user_roles do
def <<(new_item)
super( Array(new_item) - proxy_association.owner.roles )
end
end
end
, если super не работает, вам может потребоваться настроить alias_method_chain.
Это создаст только одну ассоциацию в базе данных, даже если названный многократно Направят руководство направляющих .
user.roles=[Role.first]
Я думаю, что правильное правило проверки находится в вашей модели соединения users_roles:
validates_uniqueness_of :user_id, :scope => [:role_id]
Возможно, можно создать правило проверки
validates_uniqueness_of :user_roles
, затем перехватить исключение проверки и продолжить корректно. Однако это кажется действительно хакерским и очень неэлегантным, если вообще возможно.