我有以下型号
class Backup < ActiveRecord::Base
belongs_to :component
belongs_to :backup_medium
def self.search(value)
join_tables = "backups, components, backup_media"
joins = "backups.backup_medium_id = backup_media.id and components.id = backups.component_id"
c = Backup.find_by_sql "select * from #{join_tables} where components.name like '%#{value}%' and #{joins}"
b = Backup.find_by_sql "select * from #{join_tables} where backup_media.name like '%#{value}%' and #{joins}"
c.count > 0 ? c : b
end
end
在pry中,当我运行Backup.all.class时,我得到了
=> Backup::ActiveRecord_Relation
但是当我运行Backup.search('xxx')。class时,我得到了
=> Array
由于搜索应该返回所有的子集,我想我需要返回一个Active Record_Relation。我错过了什么?
答案 0 :(得分:1)
find_by_sql
返回一个对象数组,而不是Relation
。如果要返回关系以保持一致性,请尝试重写搜索以使用ActiveRecord
api:
def self.search(value)
query = Backup.includes(:component, :backup_medium)
by_component_name = query.where("components.name like ?", "'%#{value}%'")
by_media_name = query.where("backup_media.name like ?", "'%#{value}%'")
by_component_name.any? ? by_component_name : by_media_name
end
或者,如果您仍想使用sql,可以尝试获取记录ID,然后再进行第二次查询:
def self.search(value)
# ...
c = Backup.find_by_sql "select id from #{join_tables} where components.name like '%#{value}%' and #{joins}"
b = Backup.find_by_sql "select id from #{join_tables} where backup_media.name like '%#{value}%' and #{joins}"
ids = c.count > 0 ? c : b
Backup.where(id: ids)
end
答案 1 :(得分:1)
来自文档:
对您的数据库执行自定义SQL查询并返回所有 结果。结果将作为包含列的数组返回 请求封装为您调用此方法的模型的属性 从。如果您调用Product.find_by_sql,那么结果将是 在具有您在中指定的属性的Product对象中返回 SQL查询。
因此,您将获得一组备份实例。
请注意,您可能不应该这样做。在查询中使用字符串插值可以让您轻松获得SQL注入攻击并获得任何收益。此外,使用ActiveRecord示波器可以获得更大的灵活性。
def self.my_includes
includes(:components, :backup_media)
end
def self.by_component_name(name)
media_includes.where("components.name like ?", "'%#{name}%'")
end
def self.by_media_name(name)
media_includes.where("backup_media.name like ?", "'%#{value}%'")
end
def self.search(name)
by_component(name).any? ? by_component_name : by_media_name
end
然后你可以打电话
Backup.search(name)
以及
Backup.by_component_name(name)
或
Backup.by_media_name(name)
答案 2 :(得分:0)
所以我无法获得media_includes的语法,但是受到您的解决方案的启发,我已经成功使用了连接。
我创建了一个小型演示项目,它只显示与搜索相关的代码。你可以看看https://github.com/pamh09/rails-search-demo。如果您想要在解决方案上进行协作,我认为这比尝试粘贴所有代码更有效。也就是说,如果你不打扰,我确实有一个可行的解决方案。但我想看看正确的语法是什么。
以下是型号代码。很可能我只是遇到某种语法不匹配,因为我不太熟悉rails如何实现数据库魔术(显然)。
class Backup < ApplicationRecord
belongs_to :component
belongs_to :backup_medium
#---- code below does not work ---
# in pry
# pry(Backup):1> by_media('bak').any?
# (0.0ms) SELECT COUNT(*) FROM "backups" WHERE (backup_media = 'bak')
# ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: backup_media.name: SELECT COUNT(*) FROM "backups" WHERE (backup_media.name = 'bak')
def self.my_includes
includes(:component, :backup_medium)
end
def self.by_component(name)
my_includes.where("components.name = ?", name)
end
def self.by_media(name)
my_includes.where("backup_media.name = ?", name)
end
def self.search_by(name)
by_component(name).any? ? by_component_name : by_media_name
end
# ----- code below works ... call search('string') -----
# I was unable to get the like query to work without using #{name}
def self.by_component_like(name)
# Note: joins (singular).where (plural.column ...)
joins(:component).where("components.name like '%#{name}%'")
end
def self.by_media_like(name)
joins(:backup_medium).where("backup_media.name like '%#{name}%'")
end
def self.search(name)
by_component_like(name).any? ? by_component_like(name) : by_media_like(name)
end
end
并且,如代码中所述。我想不通你怎么用?与LIKE一样,查询将像LIKE&#39;%&#39; xxx&#39;%&#39;而不是&#39;%xxx%&#39;。