Rails的find_or_create由多个属性?
活动logging中有一个方便的dynamic属性叫做find_or_create_by:
Model.find_or_create_by_<attribute>(:<attribute> => "")
但是,如果我需要find_or_create多个属性呢?
假设我有一个模型来处理Group和Member之间的M:M关系,称为GroupMember。 我可以有很多实例,其中member_id = 4,但我不希望多于一次的实例,其中member_id = 4和group_id = 7我试图找出是否有可能做这样的事情:
GroupMember.find_or_create(:member_id => 4, :group_id => 7)
我意识到可能有更好的方法来处理这个问题,但是我喜欢find_or_create的方便。
一个and
可以连接多个属性:
GroupMember.find_or_create_by_member_id_and_group_id(4, 7)
(如果您不想立即保存logging,请使用find_or_initialize_by
)
编辑:上面的方法已被弃用在Rails 4中。新的方法是:
GroupMember.where(:member_id => 4, :group_id => 7).first_or_create
和
GroupMember.where(:member_id => 4, :group_id => 7).first_or_initialize
编辑2:并不是所有的这些都是从轨道只是属性特定的。
https://github.com/rails/rails/blob/4-2-stable/guides/source/active_record_querying.md
例
GroupMember.find_or_create_by_member_id_and_group_id(4, 7)
成为
GroupMember.find_or_create_by(member_id: 4, group_id: 7)
对于任何人在这个线程中绊倒,但需要find或创build一个对象的属性可能会根据情况而改变,添加以下方法到您的模型:
# Return the first object which matches the attributes hash # - or - # Create new object with the given attributes # def self.find_or_create(attributes) Model.where(attributes).first || Model.create(attributes) end
优化提示:无论您select哪种解决scheme,都要考虑为最频繁查询的属性添加索引。
在Rails 4中你可以这样做:
GroupMember.find_or_create_by(member_id: 4, group_id: 7)
和使用不同的地方:
GroupMember.where(member_id: 4, group_id: 7).first_or_create
这将在GroupMember.where(member_id: 4, group_id: 7)
上调用create
:
GroupMember.where(member_id: 4, group_id: 7).create
相反, find_or_create_by(member_id: 4, group_id: 7)
将在find_or_create_by(member_id: 4, group_id: 7)
调用create
:
GroupMember.create(member_id: 4, group_id: 7)
请在rails / rails上看到这个相关的提交 。
通过传递一个块给find_or_create
,你可以传递额外的参数,如果它是新build的,将被添加到对象中。 如果您正在validation您没有search的字段的存在,这非常有用。
假设:
class GroupMember < ActiveRecord::Base validates_presence_of :name end
然后
GroupMember.where(:member_id => 4, :group_id => 7).first_or_create { |gm| gm.name = "John Doe" }
将会创build一个名为“John Doe”的新GroupMe,如果它没有findmember_id 4
and group_id 7
你可以做:
User.find_or_create_by(first_name: 'Penélope', last_name: 'Lopez') User.where(first_name: 'Penélope', last_name: 'Lopez').first_or_create
或者只是初始化:
User.find_or_initialize_by(first_name: 'Penélope', last_name: 'Lopez') User.where(first_name: 'Penélope', last_name: 'Lopez').first_or_initialize