Rails 虚拟属性搜索或 sql 组合列搜索

Posted

技术标签:

【中文标题】Rails 虚拟属性搜索或 sql 组合列搜索【英文标题】:Rails virtual attribute search or sql combined column search 【发布时间】:2009-11-27 01:27:48 【问题描述】:

我有一个具有“first”和“last”属性的用户模型 所以例如 User.first.first #=> "查理" User.first.last #=> "棕色"

这个用户模型还有一个虚拟属性'full_name'

#user.rb
def full_name
  [first,last].join(' ')
end

def full_name=(name) #don't know what to do with people w/ middle names
  split = name.split(' ')
  self.first = split[0]
  self.last = split[1]
end

例如:

User.first.full_name = "Charlie Brown" #=> "Charlie Brown"
User.first.full_name = "Homer Simpson" #=> "Home Simpson"
User.first.save
User.first.first #=> "Homer"
User.first.last #=> "Simpson"

如果我能按那个虚拟属性搜索就好了 例如动态查找:

User.find_by_full_name('Home Simpson') # this doesn't work

查找条件示例:

User.all(:conditions => ['full_name LIKE ?', query]) #this doesn't work

我希望至少能在 SQL 语言中找到一些可以做到这一点的方法;如果也有动态虚拟属性查找,那就是馅饼上的额外香草来源。 (今年冬天有人过吗?)

我还担心要搜索的名称,例如,“Holmes”只能在“第一”列中搜索,而不能在“最后”列中搜索,例如,User.first.full_name #=> "Sherlock Holmes"

我确实尝试进行更全面的搜索:

user.rb

def self.find_by_full_name(name) #returns an array of User model
  return all if name.blank?
    
  split = name.split(' ', 2)
  output = []
  if split.length > 1
    with_scope( :find =>  :conditions => ['first LIKE ?', "%#split[0]%"] ) do
      output << all(:conditions => ['last LIKE ?', "%#split[1]%"])
      output.flatten!
    end
  elsif split.length == 1
    output << all(:conditions => ['first LIKE ?', "%#split[0]%"])
    output << all(:conditions => ['last LIKE ?', "%#split[0]%"])
    output.flatten!
  end
end

例如

User.find_by_full_name("John").map(&:full_name) #=> ["John Resig", "John Doe"]
User.find_by_full_name("Doe").map(&:full_name) #=> ["John Doe", "Philips Doeringer"]
User.find_by_full_name("John Doe").map(&:full_name) #=> ["John Doe"]

但我只是觉得这里的 find_by_full_name 方法有点笨拙。

我的意思是,如果我有一个 full_name 列,它每次都由一个后保存过滤器设置,并带有 first 和 last 的 concat。所以找到一个人的名字,尤其是对这个人的模糊记忆,是有帮助的。因此,如果我记得那个人的名字或姓氏中的“Doe”,我总是可以做一个简单的 User.find_by_full_name('Doe') 来返回尽可能多的信息以进一步确定它。

由于它是一列,如果我必须执行类似Project.find(:all,:include =&gt; :users, :conditions=&gt;['users.full_name LIKE ?', query]) 之类的操作,我可以在 find(:conditions[...]) 子句中搜索它 在哪里

#project.rb
has_many :assignments
has_many :users, :through=>:assignments

#user.rb
has_many :assignments
has_many :projects, :through => :assignments

#assignment.rb
belongs_to :user
belongs_to :project

节日快乐 否

【问题讨论】:

【参考方案1】:

您可以在 user.rb 中使用 named_scope:

named_scope :find_by_full_name, lambda |full_name| 
  :conditions => :first => full_name.split(' ').first, 
     :last => full_name.split(' ').last

那你就可以User.find_by_full_name('John Carver')

响应需求变化的新东西

named_scope :find_by_full_name, lambda |full_name| 
  :conditions => ["first LIKE '%?%' or last LIKE '%?%'", 
    full_name.split(' ').first, full_name.split(' ').last]

【讨论】:

我明白了。我想当我以这种方式搜索全名时它确实有效。 - 但再次感谢您的回答。最佳,N 我明白了。对于那个很抱歉。我改了。【参考方案2】:

我发现 Jim 的回答也很有帮助。谢谢。不过我会做些小改动。 当前的代码会使您丢失任何中间名。我下面的内容有点混乱,但保留了中间名和复合姓氏(想想 Jean-Claude van Damme)。名字之后的所有内容都在 last_name 字段中。

named_scope :find_by_full_name, lambda  |full_name| 
 :conditions => :first_name => full_name.split(' ').first, 
   :last_name => full_name.split(' ')[1, full_name.split(' ').length-1].join(' ')
   

当然欢迎任何更简洁的方式来做到这一点。

【讨论】:

以上是关于Rails 虚拟属性搜索或 sql 组合列搜索的主要内容,如果未能解决你的问题,请参考以下文章

虚拟属性验证 Rails 3

跨多个列 PostgreSQL/Rails 的慢速通配符搜索 LIKE

Rails 3 - 验证虚拟属性导致异常

如何根据模型上的虚拟属性返回的值搜索整个模型?

在 Rails 视图中显示虚拟字段

这个 Rails 3 搜索是不是容易受到 SQL 注入的攻击?