ChatGPT解决这个技术问题 Extra ChatGPT

Rails find_or_create_by 多个属性?

在活动记录中有一个方便的动态属性,称为 find_or_create_by:

Model.find_or_create_by_<attribute>(:<attribute> => "")

但是如果我需要通过多个属性来查找或创建呢?

假设我有一个模型来处理 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 想法的便利性。


D
Deepak Mahakale

多个属性可以用 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)

您可能还喜欢 github.com/seamusabshere/upsert - 第一个参数是用于查找或创建记录的属性哈希
请注意,initialize 调用 create() 而不是 new() 可能会在 first_or_create 的情况下被调用
有人可以分享这种用法的要点示例吗?我不熟悉它的位置和调用。
我恢复了 Rails 3 代码的删除,因为很多人还没有使用 Rails 4。
只是补充一点:在 Rails 4 中,find_or_create_by_*() 函数已被弃用,但 find_or_create_by() 不是。可以使用 find_or_create_by()。检查添加 github.com/rails/rails/commit/… 的提交和官方 Rails 4.2 文档的用法:guides.rubyonrails.org/v4.2.0/…
M
Marco

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

# 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

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


需要注意的一点是,这不会处理无法批量分配的属性,而 find_or_create_by 会。
马可,试试 Model.where(attributes).instance_eval{|q| q.first || q.create}
find_or_create 还具有使用事务的好处,其中 where….first || create 引入了竞争条件
我会说def self.find_or_create(attributes) self.where(attributes).first || self.create(attributes) end,这样您就不需要重复Model
@AugustinRiedinger 您也不需要 self 在方法体内(因为您要删除单词!)。
J
Juanito Fatas

在 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.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) 将在 GroupMember 上调用 create

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

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


D
Daniel Murphy

通过将块传递给 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 的 GroupMember,它将创建一个名为“John Doe”的新 GroupMember


D
Dorian

你可以做:

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