active-record中有一个方便的动态属性find_or_create_by:
模型。Find_or_create_by_ <attribute>(:<attribute> => "")
但是,如果我需要通过多个属性查找find_or_create,该怎么办呢?
假设我有一个模型来处理组和成员之间的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思想的便利性。
通过将块传递给find_or_create,您可以传递额外的参数,这些参数将在创建新对象时添加到对象中。如果您正在验证某个字段的存在,而不是通过该字段进行搜索,那么这是非常有用的。
假设:
class GroupMember < ActiveRecord::Base
validates_presence_of :name
end
then
GroupMember.where(:member_id => 4, :group_id => 7).first_or_create { |gm| gm.name = "John Doe" }
将创建一个新的GroupMember与名称“John Doe”,如果它没有找到一个与member_id 4和group_id 7
在Rails 4中,你可以做到:
GroupMember.find_or_create_by(member_id: 4, group_id: 7)
和where的用法不同:
GroupMember.where(member_id: 4, group_id: 7).first_or_create
这将调用GroupMember上的create。(member_id: 4, group_id: 7)
GroupMember.where(member_id: 4, group_id: 7).create
相反,find_or_create_by(member_id: 4, group_id: 7)将在GroupMember上调用create:
GroupMember.create(member_id: 4, group_id: 7)
请参见此相关提交rails/rails。
多个属性可以用and连接:
GroupMember.find_or_create_by_member_id_and_group_id(4, 7)
(如果您不想立即保存记录,请使用find_or_initialize_by)
编辑:上述方法在Rails 4中已弃用。新的方法是:
GroupMember.where(:member_id => 4, :group_id => 7).first_or_create
and
GroupMember.where(:member_id => 4, :group_id => 7).first_or_initialize
编辑2:并不是所有这些都从rails中分解出来了,只是特定于属性的那些。
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)