我的Member
模型first_name
和last_name
中有两个属性。我的要求是我将获得一系列全名:
["Jane Doe", "John Doe", "Foo Bar"]
并且,对于我需要的每个元素:
first_name
和last_name
(如果存在)我试图在模型范围内创建它,如下所示:
class Member < ActiveRecord::Base
scope :find_by_full_name, -> (full_name) { |full_name|
first_name = full_name.split(' ').first
last_name = full_name.split(' ').last
where(first_name: first_name, last_name: last_name)
}
它适用于字符串,但不适用于数组。我查看了这篇文章 - https://stackoverflow.com/a/8155276/4379077。看起来Rails应该检测它是一个数组还是一个字符串,并相应地处理每个类型。在一堆或控制台尝试之后(包括将元素转换为字符串)我不知道我做错了什么,或者除了创建一个范围之外我可能会采用不同的方式。任何帮助表示赞赏。
答案 0 :(得分:1)
由于范围只是Class方法的语法糖,我建议只将其创建为类方法,整个过程变得更容易/更清洁:
class Member < ActiveRecord::Base
self.find_by_full_name(array_of_names)
members = []
array_of_names.each do |name|
split_names = name.split(' ')
members.push(Member.find_by_first_name_and_last_name(split_names.first, split_names.last))
end
members.compact
end
end
如果您希望它能够接受单个名称或一组名称,您甚至可以轻松地扩展它的功能(另外一行):
class Member < ActiveRecord::Base
self.find_by_full_name(names)
members = []
names = [names] if names.is_a?(String)
names.each do |name|
split_names = name.split(' ')
members.push(Member.find_by_first_name_and_last_name(split_names.first, split_names.last))
end
members.compact
end
end
不确定您是否熟悉.compact
,但这将完成问题的"if it exists"
部分。 Member.find_by...
会将nil
值推送到members
,如果没有匹配,则.compact
会从{{1}中移除nil
值}}
答案 1 :(得分:0)
如果我正确理解您的问题,您想通过这一系列名称查找您的成员吗?
你也可以使用像
这样的东西full_names.each do |name|
first = name.split(" ").first
last = name.split(" ").last
variable = Member.find_by_first_name_and_last_name(:first_name => first,
:last_name => last)
# member_records[] << variable
# or whatever you're doing with them next.
end
您可以请求&#34; find_by&#34;有多个参数 因此 Rails - Find By with 2 fields?
答案 2 :(得分:0)
如果您想避免N + 1查询 - 我建议 - 有一次性解决方案。您可以在SQL查询中连接名字和姓氏,并将其与给定的参数进行比较。
class Member < ActiveRecord::Base
space = Arel::Nodes.build_quoted(' ')
concat_op = '||' # check which operator your database uses
first_name_space = Arel::Nodes::InfixOperation.new(concat_op, arel_table[:first_name], space)
first_name_space_last_name = Arel::Nodes::InfixOperation.new(concat_op, first_name_space, arel_table[:last_name])
scope :find_by_full_name, -> (full_name) { where(first_name_space_last_name.in(full_name)) }
end
这适用于单个字符串和数组作为参数。
注意检查数据库使用哪个运算符作为连接运算符并进行相应调整。此示例假定为||
,这适用于PostgreSQL和SQLite数据库。
答案 3 :(得分:-1)
不是很优雅,但是怎么样
class Member < ActiveRecord::Base
scope :find_by_full_name, -> (*args) {
conds = []
conds << args.count.times.map { "first_name = ? AND last_name = ?" }.join(' OR ')
args.map { |arg| arg.split(' ') }.flatten.each { |e| conds << e }
where(conds)
}
end