best_in_place with a many to many relationship in rails 4

你。 提交于 2019-12-08 02:34:24

问题


I have made a github repo that you can find here just for this question. I have 3 models:

class User < ActiveRecord::Base
  has_many :user_countries
  has_many :event_countries,
    -> { where(user_countries: {:event => true}) },
    :through => :user_countries,
    :source => :country
  has_many :research_countries,
    -> { where(user_countries: {:research => true}) },
    :through => :user_countries
    :source => :country
end

class UserCountry < ActiveRecord::Base
  belongs_to :country
  belongs_to :user
end

class Country < ActiveRecord::Base
  # ...
end

So a user should be able to choose event_countries and research_countries.

here's my users controller (nothing complicated):

 class UsersController < ApplicationController

  respond_to :html, :json
  before_action :get_user, only: [:show, :edit, :update]
  before_action :get_users, only: [:index]

  def index
  end

  def show
  end

  def edit
  end

  def update
    @user.update_attributes(user_params)
    respond_with @user
  end

  private

  def get_user
    @user = User.find(params[:id])
  end

  def get_users
    @users = User.all
  end

  def user_params
    params.require(:user).permit(:first_name, :event_countries => [:id, :name])
  end
end

And here's my user show page:

<%= best_in_place @user, :first_name %>

<p> event countries: </p>
<%= best_in_place @user, :event_countries, place_holder: "click here to edit", as: :select, collection: Country.all.map {|i| i.name} %>

<%= link_to "users index", users_path %>

So there's really nothing complicated here. I can also succesfully edit my users first name, best_in_place is working fine.

The question is: how do I edit the event_countries ? As you can see I tried to use the collection option with the countries but when I try to select a country I get the following:

    Processing by UsersController#update as JSON
  Parameters: {"user"=>{"event_countries"=>"3"}, "authenticity_token"=>"l5L5lXFmJFQ9kI/4klMmb5jDhjmtQXwn6amj1uwjSuE=", "id"=>"6"}
  User Load (0.1ms)  SELECT  "users".* FROM "users"  WHERE "users"."id" = ? LIMIT 1  [["id", 6]]
   (0.1ms)  begin transaction
   (0.1ms)  rollback transaction
Completed 500 Internal Server Error in 3ms

NoMethodError (undefined method `each' for nil:NilClass):
  app/controllers/users_controller.rb:17:in `update'

I don't understand what it's doing, I know it must be a problem with the collection option. If you need to see any file please check my repo here: https://github.com/spawnge/best_in_place_join_models_twice . I have a spent a lot of time on this any answer/suggestion would be greatly appreciated :)


update:

I have tried this:

<%= best_in_place @user, :event_country_ids, as: :select, collection: Country.all.map { |i| i.name }, place_holder: "click here to edit",  html_attrs: { multiple: true } %>

and I have added :event_country_ids to my user params:

    params.require(:user).permit(:first_name, :event_country_ids)

And now I can see all the countries but when I select one here's what I get:

Started PUT "/users/3" for 127.0.0.1 at 2014-12-18 01:19:27 +0000
Processing by UsersController#update as JSON
  Parameters: {"user"=>{"event_country_ids"=>"1"}, "authenticity_token"=>"aZAFIHgzdSL2tlFcGtyuu+XIJW3HX2fwQGHcB9+iYpI=", "id"=>"3"}
  User Load (0.1ms)  SELECT  "users".* FROM "users"  WHERE "users"."id" = ? LIMIT 1  [["id", 3]]
   (0.0ms)  begin transaction
  Country Load (0.0ms)  SELECT  "countries".* FROM "countries"  WHERE "countries"."id" = ? LIMIT 1  [["id", 1]]
  Country Load (0.0ms)  SELECT "countries".* FROM "countries" INNER JOIN "user_countries" ON "countries"."id" = "user_countries"."country_id" WHERE "user_countries"."event" = 't' AND "user_countries"."user_id" = ?  [["user_id", 3]]
  SQL (0.1ms)  DELETE FROM "user_countries" WHERE "user_countries"."user_id" = ? AND "user_countries"."country_id" = 2  [["user_id", 3]]
  SQL (0.0ms)  INSERT INTO "user_countries" ("country_id", "event", "user_id") VALUES (?, ?, ?)  [["country_id", 1], ["event", "t"], ["user_id", 3]]
   (20.9ms)  commit transaction
Completed 204 No Content in 28ms (ActiveRecord: 21.3ms)

As you can see it seems that it insert the right content: INSERT INTO "user_countries" ("country_id", "event", "user_id") VALUES (?, ?, ?) [["country_id", 1], ["event", "t"], ["user_id", 3]] However I get the Completed 204 No Content just after that. I don't understand when I refresh the page the input is empty. Any suggestion ?


Update 2:

I checked in the console and it works, I can add event_countries to a user. However it doesn't display the user's event_countries when I refresh the page, I guess that's because I'm using the event_country_ids object.


回答1:


I think the following code should work:

<%= best_in_place @user, :event_country_ids, as: :select, 
  collection: Country.all.each_with_object({}) { |i, memo| memo[i.id] = i.name }, 
  place_holder: "click here to edit",
  html_attrs: { multiple: true } %>

Assuming you want the user to be able to assign multiple event_countries.

Reference

  • http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many, specifically the collection_singular_ids= method created by has_many.
  • https://github.com/bernat/best_in_place#select, the structure of the collection needs to be a hash. For each key => value pair, the key is what's submitted with the form and the value is what's displayed to the user.
  • http://ruby-doc.org/core-2.1.5/Enumerable.html#method-i-each_with_object, each_with_object is a part of the core Ruby library.


来源:https://stackoverflow.com/questions/27528990/best-in-place-with-a-many-to-many-relationship-in-rails-4

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!