如何在Rails 4中通过关联查询数据?

5

我希望能够获取与搜索关键字匹配的主题名称的所有配置文件。现在我正在加载所有配置文件。请问如何实现?非常感谢任何帮助。

Profile.rb

has_many :categorizations
has_many :subjects, through: :categorizations

Subject.rb

has_many :categorizations
has_many :profiles, through: :categorizations

Categorization.rb

belongs_to :profile
belongs_to :subject

views/search/index.html.erb

# search form
<%= form_tag search_index_path, :method => 'get' do %>
  <%= text_field_tag :search, params[:search] %>
  <%= submit_tag "search", :name => nil %>
<% end %>

# search results
<% @profiles.each do |profile| %>
  <%= profile.name %>
<% end %>

search_controller.rb

def index
  @profiles = Profile.with_translations('en').all
end

1
您是否需要搜索关键字与个人资料主题完全匹配? - Teddy
不是完全匹配,如果主题名称有一个单词匹配,则仍应在搜索结果中显示配置文件。 - Murtza
3个回答

4

需要补充的是,Rails 中的 全文搜索 概念。如果你正在进行搜索,你需要知道你实际上在数据库中执行的是一个全文 "搜索" 查询,这取决于你使用的 SQL 引擎不同。


MYSQL全文搜索

LIKE %{search}% 机制是MYSQL非常基本的全文搜索功能,基本上是在数据库中查找您的目标查询。这意味着,如果您的查询如下:

SELECT * FROM `products` WHERE `name` LIKE '%alligator%'

MYSQL基本上会查看整个“name”记录,以查找与您的查询相关的任何引用。结果将基于您的记录中是否有单词“鳄鱼”的任何部分。这个参考解释了更多关于此的内容。


PostgreSQL全文搜索

我写这篇文章的原因是因为PSQL实际上是以不同的方式处理全文搜索的,因此你所提供的查询只适用于MYSQL。PSQL有很多不同的函数来处理全文搜索,但由于我们使用Heroku,我们成功地使用了Textacular gem使其正常工作。

以下是PSQL处理全文搜索的一些方法:

在PostgreSQL中进行全文搜索基于匹配运算符@@,如果tsvector(文档)与tsquery(查询)匹配,则返回true。无论先写哪种数据类型都可以:

SELECT 'a fat cat sat on a mat and ate a fat rat'::tsvector @@ 'cat &
rat'::tsquery;  ?column?
----------  t

SELECT 'fat & cow'::tsquery @@ 'a fat cat sat on a mat and ate a fat
rat'::tsvector;  ?column?
----------  f 

正如上面的例子所示,一个tsquery不仅仅是原始文本,就像一个tsvector一样。tsquery包含搜索术语,这些术语必须是已经标准化的词汇,并且可以使用AND、OR和NOT运算符组合多个术语。(详情请参见第8.11节) 有一些函数to_tsquery和plainto_tsquery,这些函数有助于将用户编写的文本转换为正确的tsquery,例如通过标准化文本中出现的单词。同样,to_tsvector用于解析和标准化文档字符串。因此,在实践中,文本搜索匹配看起来更像是这样:
SELECT to_tsvector('fat cats ate fat rats') @@ to_tsquery('fat & rat');  ?column? 
----------  t Observe that this match would not succeed if written as

SELECT 'fat cats ate fat rats'::tsvector @@ to_tsquery('fat & rat'); ?column? ---------- f

查询语句:判断文本中是否包含“fat”和“rat”,返回结果为布尔值f。

全文搜索软件

全文搜索在数据库中本质上是非常昂贵的,特别是当你需要搜索大量数据时。这就是为什么像sunspot solrsphinx这样的解决方案存在的原因——提供一种索引和搜索数据的方法。

如果你的应用程序变得非常流行,你可能希望投资其中一个全文搜索系统,例如Heroku演示的这些系统

Heroku's full text search packages


非常感谢您提供如此详细的答案,但实际上我是Rails的新手,正在尝试理解如何通过关联进行搜索,但我发现您的答案是一个不错的选择,让我在新应用程序中尝试一下。我正在尝试使用Sunspot,参考Ryan的Railscast。 - Murtza
2
没问题!如果你是Rails的新手,我不会建议你立即实现“硬核”的全文搜索功能(需要一些工作才能使其正常工作)。我想做的是给你一个定义,让你知道你实际上要做什么;而不是只给你一个查询,当你提高技能时,你将拥有一个准备好实现的功能集 :) - Richard Peck
1
经过几天的练习,我成功地使用了Sunspot gem。感谢你的指导。我有一个问题,我能在使用Sunspot gem的同时使用globalize gem吗? - Murtza
1
我不确定你是否可以同时使用这两个宝石 - 为什么不提一个新问题呢? :) - Richard Peck
这里是一个新问题:如何添加 Globalize 和 Sunspot Solr 的翻译。 - Murtza

4
@profiles = Subject.where("name LIKE ?", "%#{params[:search]}%").map(&:profiles)

1
我得到了以下结果:“Mysql2 :: Error:'field list'中没有'profile_id'列:SELECT profile_id FROMsubjectsWHERE(name LIKE'%%')”。 - Murtza
现在我得到了“undefined method `model_name' for”的错误,并且结果中没有打印出profile.name。 - Murtza

3

请检查是否有效。

@profiles = Profile.joins(:subjects).where("subject.name like '%?%'",params[:search])

不,它没有工作,并给我以下错误"Mysql2 :: Error:您的SQL语法有误;请检查与您的MySQL服务器版本相对应的手册以了解在第1行处使用正确的语法:SELECT profiles.* FROM profiles INNER JOIN categorizations ON categorizations.profile_id = profiles。'。'id' INNER JOIN subjects ON subjects。'。'id' = categorizations。'。'subject_id' WHERE (subject.name like %''%)" - Murtza
1
@Murtza 已编辑。同时,请将 params[:search] 替换为您的搜索查询。 - Siva
1
你能发布一下你执行的查询吗? - Siva
2
@profiles = Profile.joins(:subjects).where("subject.name like '%?%'","数学") - Siva
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接