Ruby-on-rails Rails find_or_create_by 不止一个属性?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3046607/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Rails find_or_create_by more than one attribute?
提问by tybro0103
There is a handy dynamic attribute in active-record called find_or_create_by:
active-record 中有一个方便的动态属性叫做 find_or_create_by:
Model.find_or_create_by_<attribute>(:<attribute> => "")
Model.find_or_create_by_<attribute>(:<attribute> => "")
But what if I need to find_or_create by more than one attribute?
但是如果我需要通过多个属性 find_or_create 怎么办?
Say I have a model to handle a M:M relationship between Group and Member called GroupMember. I could have many instances where member_id = 4, but I don't ever want more than once instance where member_id = 4 and group_id = 7. I'm trying to figure out if it's possible to do something like this:
假设我有一个模型来处理 Group 和 Member 之间的 M:M 关系,称为 GroupMember。我可以有很多 member_id = 4 的实例,但我不想要不止一次 member_id = 4 和 group_id = 7 的实例。我想弄清楚是否有可能做这样的事情:
GroupMember.find_or_create(:member_id => 4, :group_id => 7)
I realize there may be better ways to handle this, but I like the convenience of the idea of find_or_create.
我意识到可能有更好的方法来处理这个问题,但我喜欢 find_or_create 的想法带来的便利。
回答by x1a4
Multiple attributes can be connected with an and:
多个属性可以与一个连接and:
GroupMember.find_or_create_by_member_id_and_group_id(4, 7)
(use find_or_initialize_byif you don't want to save the record right away)
(find_or_initialize_by如果您不想立即保存记录,请使用)
Edit:The above method is deprecated in Rails 4. The new way to do it will be:
编辑:上述方法在 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
Edit 2:Not all of these were factored out of rails just the attribute specific ones.
编辑 2:并非所有这些都被排除在 Rails 之外,只是特定于属性的那些。
https://github.com/rails/rails/blob/4-2-stable/guides/source/active_record_querying.md
https://github.com/rails/rails/blob/4-2-stable/guides/source/active_record_querying.md
Example
例子
GroupMember.find_or_create_by_member_id_and_group_id(4, 7)
became
变成了
GroupMember.find_or_create_by(member_id: 4, group_id: 7)
回答by Marco
For anyone else who stumbles across this thread but needs to find or create an object with attributes that might change depending on the circumstances, add the following method to your model:
对于偶然发现此线程但需要查找或创建属性可能因情况而异的对象的其他任何人,请将以下方法添加到您的模型中:
# 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
Optimization tip:regardless of which solution you choose, consider adding indexes for the attributes you are querying most frequently.
优化提示:无论您选择哪种解决方案,请考虑为您最常查询的属性添加索引。
回答by Juanito Fatas
In Rails 4 you could do:
在 Rails 4 中,你可以这样做:
GroupMember.find_or_create_by(member_id: 4, group_id: 7)
And use whereis different:
并且用途where不同:
GroupMember.where(member_id: 4, group_id: 7).first_or_create
This will call createon GroupMember.where(member_id: 4, group_id: 7):
这将调用create上GroupMember.where(member_id: 4, group_id: 7):
GroupMember.where(member_id: 4, group_id: 7).create
On the contrary, the find_or_create_by(member_id: 4, group_id: 7)will call createon GroupMember:
相反,在find_or_create_by(member_id: 4, group_id: 7)将调用create上GroupMember:
GroupMember.create(member_id: 4, group_id: 7)
Please see this relevant commiton rails/rails.
请在 rails/rails 上查看此相关提交。
回答by Daniel Murphy
By passing a block to find_or_create, you can pass additional parameters that will be added to the object if it is created new. This is useful if you are validating the presence of a field that you aren't searching by.
通过将块传递给find_or_create,您可以传递额外的参数,如果对象是新创建的,这些参数将被添加到对象中。如果您要验证不是搜索依据的字段的存在,这将很有用。
Assuming:
假设:
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" }
will create a new GroupMember with the name "John Doe" if it doesn't find one with member_id 4and group_id 7
如果没有找到一个名为“John Doe”的新 GroupMember,它将创建一个 member_id 4and group_id 7
回答by Dorian
You can do:
你可以做:
User.find_or_create_by(first_name: 'Penélope', last_name: 'Lopez')
User.where(first_name: 'Penélope', last_name: 'Lopez').first_or_create
Or to just initialize:
或者只是初始化:
User.find_or_initialize_by(first_name: 'Penélope', last_name: 'Lopez')
User.where(first_name: 'Penélope', last_name: 'Lopez').first_or_initialize

