Rails find_or_create_by多个属性?

时间:2010-06-15 15:27:01

标签: ruby-on-rails activerecord model many-to-many dynamic-attributes

活动记录中有一个名为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这个想法的便利。

5 个答案:

答案 0 :(得分:457)

可以使用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

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)

答案 1 :(得分:32)

对于偶然发现此线程但需要查找或创建具有可能根据具体情况而变化的属性的对象的其他人,请将以下方法添加到模型中:

# 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

优化提示,无论您选择哪种解决方案,请考虑为您最常查询的属性添加索引。

答案 2 :(得分:27)

在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

这会在create上致电GroupMember.where(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)会在create上致电GroupMember

GroupMember.create(member_id: 4, group_id: 7)

请在rails / rails上查看相关的commit

答案 3 :(得分:14)

通过将块传递给find_or_create,您可以传递将在创建新对象时添加到对象的其他参数。如果您要验证是否存在未搜索的字段,则此功能非常有用。

假设:

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" }

如果找不到member_id 4 and group_id 7

,则会创建一个名为“John Doe”的新GroupMember

答案 4 :(得分:4)

你可以这样做:

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