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:
id
matches the many-to-many table's source_id
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.