Rails搜索has_many关系

时间:2017-03-22 21:50:38

标签: ruby-on-rails activerecord devise

Heyo。一直试图解决这个问题,但我已经被困了太长时间而且只是变得痛苦!

我正在尝试使用“高级搜索”表单,允许您根据其他模型中的设置搜索“用户”。例如搜索名为Jim的用户,他做跑步,减肥作为他的目标。

我有三种模式:

  • 用户(使用设计)
  • 运动(与用户多对多)
  • 目标(用户has_many目标,目标belongs_to用户)

到目前为止,我已设法使其工作,因此我可以通过选择框搜索用户模型中的内容(例如名称)以及用户体育。我无法工作的是搜索用户目标,我不明白为什么。

我只能搜索目标而没有其他字段时,“没有人似乎有这些偏好”。

我尝试使用与我的体育相同的代码,但这不起作用(猜测因为不同的关系?)

# searches/show.html.erb
<% if @search.search_users.empty? %>

  <p>Nobody seems to have these preferences</p>

<% else %>
<% @search.search_users.each do |u| %>
  <tr>
   <td><%= u.name %></td>

    <% u.sports.each do |s| %>
     <td><%= s.name %></td>
    <% end %>

    <% u.goals.each do |g| %>
     <td><%= g.name %></td>
    <% end %>

  </tr>
<% end %>

我在控制台中完成了关联,当我输入例如u.goals时,我得到了这个(当我查询用户与目标相关联时,反之亦然):

irb(main):015:0> u.goals
=> #<ActiveRecord::Associations::CollectionProxy [#<Goal id: 1, name: "Weight Loss", user_id: 1>, #<Goal id: 3, name: "Strength", user_id: 1>]>

这是我目前的代码:

# user.rb
class User < ApplicationRecord
 has_and_belongs_to_many :sports
 has_many :goals, :foreign_key => :goal_id
end

# sport.rb
class Sport < ApplicationRecord
 has_and_belongs_to_many :users
end

# goal.rb
class Goal < ApplicationRecord
 belongs_to :user, :foreign_key => :goal_id
end

我的搜索内容:

# search.rb
def search_users
 users = User.all
 users = users.where("users.name ILIKE ?", "%#{keywords}%") if  keywords.present?
 users = users.joins(:sports).where("sports.name ILIKE ?", "%#{name}%") if name.present?
 users = users.where(goal_id: goal_id) if goal_id.present?
 return users
end

# searches/new.html.erb
<%= form_for @search do |s| %>
  <div class="form-group">
    <%= s.label :keywords %>
    <%= s.text_field :keywords %>
  </div>

  <div class="form-group">
    <%= s.label :exercise %>
    <%= s.select :name, options_for_select(@s_names), include_blank: true %>
  </div>

  <div class="form-group">
    <%= s.label :goals %>
    <%= s.collection_select :goal_id, Goal.order(:name), :id, :name, include_blank: true %>
  </div>
  <%= s.submit "Search", class: "btn btn-primary" %>
<% end %>

# searches_controller.rb
class SearchesController < ApplicationController
  def new
    @search = Search.new
    @s_names = Sport.uniq.pluck(:name)
    @users = User.uniq.pluck(:name)
  end

   def create
    @search = Search.create(search_params)
    redirect_to @search
  end

  def show
    @search = Search.find(params[:id])
  end

  private
  def search_params
   params.require(:search).permit(:keywords, :name, :goal_id)
 end
end

然后我的架构供参考:

create_table "goals", force: :cascade do |t|
    t.string  "name"
    t.integer "user_id"
    t.index ["user_id"], name: "index_goals_on_user_id", using: :btree
  end

  create_table "searches", force: :cascade do |t|
    t.string   "keywords"
    t.string   "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer  "goal_id"
    t.index ["goal_id"], name: "index_searches_on_goal_id", using: :btree
  end

  create_table "sports", force: :cascade do |t|
    t.string   "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "sports_users", id: false, force: :cascade do |t|
    t.integer "user_id",  null: false
    t.integer "sport_id", null: false
    t.index ["user_id", "sport_id"], name: "index_sports_users_on_user_id_and_sport_id", using: :btree
  end

  create_table "users", force: :cascade do |t|
    t.string   "email",                  default: "", null: false
    t.string   "encrypted_password",     default: "", null: false
    t.string   "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          default: 0,  null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.inet     "current_sign_in_ip"
    t.inet     "last_sign_in_ip"
    t.datetime "created_at",                          null: false
    t.datetime "updated_at",                          null: false
    t.string   "name"
    t.integer  "movement_id"
    t.integer  "goal_id"
    t.index ["email"], name: "index_users_on_email", unique: true, using: :btree
    t.index ["goal_id"], name: "index_users_on_goal_id", using: :btree
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
  end

  add_foreign_key "goals", "users"
end

对于大量凌乱的代码非常抱歉,但我现在只是绊倒自己而感到困惑。

提前谢谢你。

1 个答案:

答案 0 :(得分:0)

我会改变

r = 1

users = users.where(goal_id: goal_id) if goal_id.present?

对于高级搜索,我最近使用了本文中提到的方法:http://www.justinweiss.com/articles/search-and-filter-rails-models-without-bloating-your-controller/,如果您考虑扩展搜索选项,我认为值得一读。

编辑:以下评论中的完整回复 需要删除users = users.joins(:goals).where(goals: {id: goal_id})