Rails 4 - best_in_place gem and many-to-many association

◇◆丶佛笑我妖孽 提交于 2019-12-10 09:44:53

问题


I am struggling to add the ability to update a contact languages using best_in_place (a jQuery inplace-editor gem).

I have a contact object, a language object and a has_and_belongs_to_many :languages relationship between contacts and languages. Therefore, a has_and_belongs_to_many implied a join table between the contacts and the languages tables. To sum up quickly, I have something like this:

    contacts             contacts_languages             languages
+------+--------+   +------------+-------------+   +------+------------+
|  id  |  name  |   | contact_id | language_id |   |  id  |    name    |
+------+--------+   +------------+-------------+   +------+------------+
|   1  |  John  |   |     1      |      2      |   |   1  |      EN    | 
|   2  |  Mike  |   |     1      |      3      |   |   2  |      FR    |
|   3  |  Dick  |   |     2      |      1      |   |   3  |      DE    |
+------+--------+   |     3      |      1      |   |   4  |      ES    |
                    |     3      |      5      |   |   5  |      ZH    |
                    |     3      |      6      |   |   6  |      JP    |
                    +------------+-------------+   +------+------------+

Now, to display and edit a contact languages, I am using a form in which I have:

- @contact.languages.uniq.each_with_index do |lang, index|
    = best_in_place lang, :name, type: :select, collection: @all_languages.map { |name| [name.id, name.name] }, classes: "#{'empty' if lang.blank?}"

Note that I am using slim template engine here.

@contact is set in the controller to Contact.find(params[:id]) @contact.languages return an ActiveRecord of #language objects @all_languages is set in the controller to Language.order("name ASC")

Also, note that @contact.language_ids would print an array the language_id of @contact and I am using @contact.update_attributes(language_ids: [1, 2, 3]) to set a contact languages.

The current source code above works to display languages, but do not work when it comes to update them as lang is used as an object by best_in_place. Therefore, I will end up not updating the *contacts_languages* table but the languages table instead like this:

     languages
+------+------------+
|  id  |    name    |
+------+------------+
|   1  |      1     | 
|   2  |      FR    | 
|   3  |      DE    | 
|   4  |      ES    | 
|   5  |      ZH    | 
|   6  |      JP    | 
+------+------------+

where name has been replaced by the id of the language that was supposed to be set to the contacts_languages table.

Do you have any idea how could I update the *contacts_languages* table instead for the edited language? And everything using best_in_place if possible.

Thanks!

EDIT

contact.rb

# == Schema Information
#
# Table name: contacts
#
#  id                    :integer         not null, primary key
#  first_name            :string(255)
#  last_name             :string(255)
#  title                 :string(255)
#  age                   :float
#  gender                :integer
#  active                :integer
#  info                  :text
#  created_at            :datetime        not null
#  updated_at            :datetime        not null
#  user_id               :integer
#  slug                  :string(255)
#  account_id            :integer
#  image                 :string(255)
#  uid                   :integer
#  tracking_friend_token :string(255)
#  tracking_friend_id    :string(255)
#  user_token            :string(255)
#  job_title             :string(255)
#  dob                   :date
#  marital_status        :integer
#

class Contact < ActiveRecord::Base

  include PublicActivity::Model
  tracked except: :destroy, 
          owner: Proc.new{ |controller, model| controller.current_user },
          recipient: ->(controller, model) { model && model }

  include PgSearch
  pg_search_scope :search, against: [:first_name, :last_name, :uid],
    associated_against: { email_addresses: :email }

  after_create :set_defaults

  attr_accessible :first_name, :last_name, :title, :age, :gender, :active, :info, :user_id, :type_list, :industry_list, :tag_list, :category_list, :phone_numbers_attributes, :email_addresses_attributes, :social_networks_attributes, :addresses_attributes, :websites_attributes, :instant_messengers_attributes, :company_ids, :language_ids, :user_ids, :slug, :account_id, :image, :uid, :tracking_friend_token, :tracking_friend_id, :job_title, :dob, :marital_status, :children_attributes, :important_dates_attributes, :user_token

  #Will Paginate default
  self.per_page = 100

  acts_as_tenant(:account)
  acts_as_taggable
  acts_as_taggable_on :type, :industries, :categories

  has_many :addresses
  has_many :alerts
  has_many :attachments
  has_many :call_requests
  has_many :children
  has_many :comments
  has_many :contact_companies
  has_many :email_addresses
  has_many :important_dates
  has_many :instant_messengers
  has_many :phone_numbers
  has_many :pushes
  has_many :social_networks
  has_many :websites

  has_many :companies, through: :contact_companies
  has_and_belongs_to_many :languages
  has_and_belongs_to_many :users

  accepts_nested_attributes_for :addresses, :reject_if => proc { |attributes| attributes['address_line_1'].blank? }, :allow_destroy => true
  accepts_nested_attributes_for :attachments, :reject_if => proc { |a| a['file'].blank? }, :allow_destroy => true
  accepts_nested_attributes_for :children, :reject_if => proc { |a| a['first_name'].blank? }, :allow_destroy => true
  accepts_nested_attributes_for :comments, :reject_if => proc { |a| a['comment'].blank? }, :allow_destroy => true
  accepts_nested_attributes_for :email_addresses, :reject_if => proc { |a| a['email'].blank? }, :allow_destroy => true
  accepts_nested_attributes_for :important_dates
  accepts_nested_attributes_for :instant_messengers, :reject_if => proc { |a| a['name'].blank? }, :allow_destroy => true
  accepts_nested_attributes_for :languages, :reject_if => proc { |a| a['iso'].blank? }, :allow_destroy => true
  accepts_nested_attributes_for :phone_numbers, :reject_if => proc { |a| a['number'].blank? }, :allow_destroy => true
  accepts_nested_attributes_for :social_networks, :reject_if => proc { |a| a['name'].blank? }, :allow_destroy => true
  accepts_nested_attributes_for :websites, :reject_if => proc { |a| a['url'].blank? }, :allow_destroy => true

  validates :first_name, :presence => true
  validates :last_name,  :presence => true
  validates :active,     :presence => true

  def reference_id
    "ID-USR-000000#{self.id}"
  end

  def fullname
    "#{first_name.titleize} #{last_name.titleize}"
  end

  def set_defaults
    type_list = "Customer" unless self.type_list.present?
    language_ids = 1 unless self.language_ids.present?
    self.update_attributes(language_ids: language_ids, type_list: type_list)
  end

  #Postgres fulltext search
  def self.text_search(query)
    if query.present?
      search(query)
    else
      scoped
    end
  end

end

language.rb

# == Schema Information
#
# Table name: languages
#
#  id         :integer         not null, primary key
#  name       :string(255)
#  iso        :string(255)
#  contact_id :integer
#  company_id :integer
#  created_at :datetime        not null
#  updated_at :datetime        not null
#

class Language < ActiveRecord::Base

  attr_accessible :name, :iso

  has_and_belongs_to_many :contacts

  validates :name,  presence: true, uniqueness: true
  validates :iso,   presence: true, uniqueness: true

  default_scope order("name ASC")

end

回答1:


I think the following could be your best bet. I tried doing it in a more "Rails" way, but BIP won't allow it.

View

    <% @contact.languages.uniq.each_with_index do |lang, index| %>
     <%= best_in_place lang, :id, 
         type: :select, 
         path: "/contacts/bip/#{@contact.id}/#{lang.id}",
         collection: @all_languages.map { |i| [i.id, i.name] } %> 
   <% end %>

contacts_controller

def bip
    @contact = Contact.find(params[:c_id])
    ContactsLanguage.where({contact_id: params[:c_id],language_id: params[:l_id]}).delete_all
    ContactsLanguage.create! contact_id: params[:c_id], language_id: params[:language][:id]

    respond_to do |format|
      format.json { render json: @contact }
    end

  end

routes

 match '/contacts/bip/:c_id/:l_id' => 'contacts#bip'


来源:https://stackoverflow.com/questions/21184592/rails-4-best-in-place-gem-and-many-to-many-association

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