简体   繁体   中英

what is the proper way to handle many to many helper views in rails?

I need to add a select box next to each field in a create/update form which establishes its provenance. There is a table with photographer info, a table with sources, and a table establishing a many to many relation between them. A relation would take the id of a photographer, the column in that record (say, "last" for the lastname) and an id for the source where that information came from (the data in the table comes from different sources in a very fine-grained way).

What is the best way of adding a select box next to every field in the create/update form for a photographer so as to select where that info comes from?

I am using Ruby on Rails 3.0.3 with the mysql2 connector.

Right now this is the snippet I have to show a given column's source (incomplete since it is missing a way to show the column name):

Source: <%= collection_select("photographers_sources","source_id",Source.all, :id, :name, {:include_blank => 'None'})%><br />

But I don't know how to:

  1. pre-select the source whose id matches the many-to-many table's source_id
  2. send that data back ( column and source_id ) and perform the association in the database

My schema:

ActiveRecord::Schema.define(:version => 0) do

  create_table "photographers", :force => true do |t|
    t.string  "first"
    t.string  "last"
    ...
  end

  create_table "photographers_sources", :force => true do |t|
    t.string  "photographer_column", :limit => 32, :default => "", :null => false
    t.integer "source_id",                                         :null => false
    t.integer "photographer_id",                                   :null => false
    t.string  "extra"
  end

  add_index "photographers_sources", ["photographer_id"], :name => "photographer_id"
  add_index "photographers_sources", ["source_id"], :name => "source_id"

  create_table "sources", :force => true do |t|
    t.string "name"
  end

end

My models:

class Photographer < ActiveRecord::Base
  validates :first,  :presence => true
  has_many :photographers_sources, :dependent => :destroy
  has_many :sources, :through => :photographers_sources

  def sourcelist
    PhotographersSource.where(:photographer_id => id)
  end
end

class Source < ActiveRecord::Base
  validates :name,  :presence => true
  has_many :photographers_sources, :dependent => :destroy
  has_many :photographers, :through => :photographers_sources
end

class PhotographersSource < ActiveRecord::Base
  belongs_to :photographer
  belongs_to :source
  validates :photographer_column,  :presence => true
  validates :source_id, :presence => true,
                        :numericality => { :only_integer => true }
  validates :photographer_id, :presence => true,
                        :numericality => { :only_integer => true }
end

I added a form partial with the select box for the source:

<%
if @photographer.sourcelist.select{|s| s.photographer_column==column}.length != 0
    @id_to_select = @photographer.sourcelist.select{|s| s.photographer_column==column}[0].source_id
else
    @id_to_select = 0
end
%>

Source: <%= collection_select("photographers_sources_plain", column, Source.all, :id, :name, {:include_blank => 'None', :selected => @id_to_select })%><br />

This is placed next to each field like so:

<%= render (:partial => 'source_form', :locals => {:column => 'category'}) %>

You would change "category" to whatever the field name is. I'm sure there must be a better way but that's good enough for me.

Note that the name generated in the select is "photographers_sources_plain[column]" so in the controller I have in the update action:

params[:photographer][:photographers_sources] = []
plain_sources = params[:photographers_sources_plain]
plain_sources.each do |key, value|
  if value != ""
    params[:photographer][:photographers_sources] << PhotographersSource.new(:photographer_column=>key,:source_id=>value.to_i)
  end
end

An equivalent addition is needed for the new action. Once again, I'm sure there must be a better way but I'm new to Rails so this is what I could manage to do.

This takes care of everything pretty well. Hope this helps someone else.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM