I'm new to Rails development, so please bear with me. I'm creating a view that has several fields on it that look very similar. It's just begging to be refactored somehow but I haven't been able to figure it out. See code sample below:
<%= form_for(#tapelog) do |f| %>
<div class="container">
<div class="field span-16">
<div class="span-8 labelRight">
<%= f.label :client %>
</div>
<div class="span-8 last">
<%= f.collection_select :client_id, Client.find(:all), :id, :name,
{ :prompt => "Select a Client..." },
{ :class => "automatixSelect" } %>
</div>
</div>
<div class="field span-16">
<div class="span-8 labelRight">
<%= f.label :employer %>
</div>
<div class="span-8 last">
<%= f.collection_select :employer_id, Employer.find(:all), :id, :name,
{ :prompt => "Select an Employer..." },
{ :class => "automatixSelect" } %>
</div>
</div>
....
<% end %>
There are about 7 fields like that. I tried to put them all into partials just so I could reduce the clutter on this page but that errors out because 'f' is not defined. Any ideas on how I could reduce some of the clutter here? Any other tips in general on Ruby refactoring would also be welcome.
Thanks,
-- A.
If you want to use the 'f' in the subsequent partials, pass it as a parameter
<%= render :partial => :some_partial, :locals => { :f => f } %>
The first thing I'd do is rename the "f" local variable to "form" for clarity. Then, extracting the code to a partial is reasonable:
<div class="field span-16">
<div class="span-8 labelRight">
<%= form.label :employer %>
</div>
<div class="span-8 last">
<%= form.collection_select :employer_id, Employer.find(:all), :id, :name,
{ :prompt => "Select an Employer..." },
{ :class => "automatixSelect" } %>
</div>
</div>
It looks to me like this is a belongs_to relationship, so I might create a partial called "belongs_to" and render it like:
<%= render :belongs_to, :parent => :employer, :form => form %>
The idea is we'll have a local named "parent" that we can alter in the partial. Note that I used the shorthand partial syntax. It's the same as:
<%= render :partial => :belongs_to, :locals => { :parent => :employer, :form => form } %>
<div class="field span-16">
<div class="span-8 labelRight">
<%= form.label parent %>
</div>
<div class="span-8 last">
<%= form.collection_select :"#{parent}_id", parent.to_s.capitalize.constantize.find(:all), :id, :name,
{ :prompt => "Select an #{parent.to_s.capitalize}..." },
{ :class => "automatixSelect" } %>
</div>
</div>
Related
I am trying to have my Edit form only allow for the creation of new elements. Currently it automatically displays all of the existing elements. Below is my current code. I have a standard has_many, belongs_to relationship between Orders and Documents. I only want the ability for users to add new documents and never edit the existing documents. With the current code It displays all associated Documents on the edit form.
<%= f.fields_for :documents, child_index: Time.now.to_i do |document| %>
<div class="col-md-5">
<%= document.label :doc_type, "Type", :style => "color:red;" %>
<%= document.collection_select :doc_type_id, DocType.order(:name), :id, :name, { prompt: true, class: "form-full"} %>
<br>
</div>
<div class="col-md-7">
<%= document.label :description,"Description **", :style => "color:red;" %>
<%= document.text_field :description, style:"color:black;" %>
<br>
</div>
<div class="col-md-12">
<br>
<%= document.file_field :doc, style:"color:white;" %>
</div>
<div class="col-md-12" style="background:#272727;">
<hr class="style2">
</div>
<% end %>
class Order < ActiveRecord::Base
belongs_to :user
has_many :properties, :dependent => :destroy
has_many :documents, :dependent => :destroy
accepts_nested_attributes_for :documents,
:allow_destroy => true,
:reject_if => :all_blank
accepts_nested_attributes_for :properties,
reject_if: proc { |att| att["city"].blank? }
end
class Document < ActiveRecord::Base
belongs_to :order
belongs_to :doc_type
end
With The below code I was able to have the form appear correctly (not showing existing Documents) but when adding a new Document via the Edit form, the Document is never actually created.
<% if !current_page?(action: 'edit') %>
<%= f.fields_for :documents, child_index: Time.now.to_i do |document| %>
<div class="col-md-5">
<%= document.label :doc_type, "Type", :style => "color:red;" %>
<%= document.collection_select :doc_type_id, DocType.order(:name), :id, :name, { prompt: true, class: "form-full"} %>
<br>
</div>
<div class="col-md-7">
<%= document.label :description,"Description **", :style => "color:red;" %>
<%= document.text_field :description, style:"color:black;" %>
<br>
</div>
<div class="col-md-12">
<br>
<%= document.file_field :doc, style:"color:white;" %>
</div>
<div class="col-md-12" style="background:#272727;">
<hr class="style2">
</div>
<% end %>
<% else %>
<%= f.fields_for #order.documents.build, child_index: Time.now.to_i do |document| %>
<div class="col-md-5">
<%= document.label :doc_type, "Type", :style => "color:red;" %>
<%= document.collection_select :doc_type_id, DocType.order(:name), :id, :name, { prompt: true, class: "form-full"} %>
<br>
</div>
<div class="col-md-7">
<%= document.label :description,"Description **", :style => "color:red;" %>
<%= document.text_field :description, style:"color:black;" %>
<br>
</div>
<div class="col-md-12">
<br>
<%= document.file_field :doc, style:"color:white;" %>
</div>
<div class="col-md-12" style="background:#272727;">
<hr class="style2">
</div>
<% end %>
<% end %>
Any help/advice/resources would be appreciated. Been stuck on this for a bit. Also I have not refactored into partials yet so please forgive the messiness.
THANKS!!
-Vinny
I have a few models Score ScoreAuthority ScoreColor and ScoreType. Score has_one authority, color, and type. Authority, color, and type each belong_to score. I am having trouble creating the form for Score.
I want users to create this relationship from Scores and everyone seems to handle only the reverse scenario creating from authorities, colors, types forms. What I mean specifically is for example:
Authorities
- foo
- bar
Colors
- red
- blue
I want the use to go into Score, chose to create a new score and then select foo from the drop down list, blue from the colors list, enter a score and submit. Authorities, colors and types will not change much and it would make any sense for the user to select Score from each of those.
When I currently do that I get the following error:
ScoreAuthority(#2248480380) expected, got String(#2155957040)
score/_form.html.erb
<%= form_for #score, :html => { :class => 'form-horizontal' } do |f| %>
<div class="control-group">
<%= f.label :product_id, "Products", :class => 'control-label' %>
<div class="controls">
<%= f.collection_select(:product_id, Product.order(:name), :id, :name) %>
</div>
</div>
<div class="control-group">
<%= f.label :score_authority, "Score Authority", :class => 'control-label' %>
<div class="controls">
<%= f.collection_select :score_authority, ScoreAuthority.order(:name), :id, :name, {}, {:class=>'chosen'} %>
</div>
</div>
<div class="control-group">
<%= f.label :score_type, "Score Types", :class => 'control-label' %>
<div class="controls">
<%#= f.collection_select(:score_type, ScoreType.order(:name), :id, :name) %>
<%= f.collection_select :score_type, ScoreType.order(:name), :id, :name, {}, {:class=>'chosen'} %>
</div>
</div>
<div class="control-group">
<%= f.label :score_color, "Score Types", :class => 'control-label' %>
<div class="controls">
<%= f.collection_select :score_color, ScoreColor.order(:name), :id, :name, {}, {:class=>'chosen'} %>
</div>
</div>
<div class="control-group">
<%= f.label :notation, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :notation, :class => 'text_field' %>
</div>
</div>
<div class="control-group">
<%= f.label :value, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :value, :class => 'text_field' %>
</div>
</div>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
scores_path, :class => 'btn' %>
</div>
<% end %>
score_authorities, score_colors, score_types tables all have score_id as a column. Each of these models also has belongs_to :score.
The score model
has_one :score_authority
has_one :score_type
has_one :score_color
Not sure what I am doing wrong here, any help would be appreciated. Thanks!
you should use :score_authority_id instead of :score_authority in form
<%= f.collection_select :score_authority_id, ScoreAuthority.order(:name), :id, :name, {}, {:class=>'chosen'} %>
<%= f.collection_select :score_color_id, ScoreColor.order(:name), :id, :name, {}, {:class=>'chosen'} %>
<%= f.collection_select :score_color_id, ScoreColor.order(:name), :id, :name, {}, {:class=>'chosen'} %>
see this How do I create the view for the has_one association? for more detail
or you can try
class Score
has_one :score_authority
accepts_nested_attributes_for :score_authority
end
<%= form_for #score ... do |f| %>
...
<%= f.fields_for :score_authority do |b| %>
<%= b.collection_select :id, ScoreAuthority.all, :id, :name %>
...
<% end %>
...
<% end %>
I have a model named Page and one named Medium. Medium is for uploaded images. The two models are connected with a rich HABTM association.
I want to be able to upload images through my page edit form. However i got a strange result. I am only getting the file field when the page already have an image associated with it. What can cause this?
This is my page model:
class Page < ActiveRecord::Base
attr_accessible :content, :title, :url, :status, :excerpt, :media_attributes
belongs_to :users
has_many :page_medium
has_many :media, :through => :page_medium
accepts_nested_attributes_for :media
acts_as_url :title, :only_when_blank => true, :sync_url => true
acts_as_list
STATUS = %w[draft published]
def to_param
"#{url}" # or whatever you set :url_attribute to
end
validates :title, :status, :url, :presence => true
end
This is my form:
<%= simple_form_for #page, :html => { :class => 'page-form' } do |f| %>
<div class="span9">
<div class="row">
<%= f.input :title, input_html: { class: 'span6'}, wrapper_html: { class: 'span6'} %>
<%= f.input :url, input_html: { class: 'span3'}, wrapper_html: { class: 'span3'} %>
</div>
<div class="tabbable"> <!-- Only required for left/right tabs -->
<ul class="nav nav-tabs">
<li class="active">Content</li>
<li>Excerpt</li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="tab1">
<%= f.input :content, label: false, input_html: { class: 'wysihtml5 span9' } %>
</div>
<div class="tab-pane" id="tab2">
<%= f.input :excerpt, label: false, input_html: { class: 'wysihtml5 span9 excerpt' }%>
</div>
</div>
</div>
</div>
<div class="span3">
<div class="well">
<fieldset>
<legend>Options</legend>
</fieldset>
<%= f.input :status , collection: Page::STATUS.map { |s| [s.humanize, s] }, prompt: '- Select page status -' %>
<div class="form-actions">
<%= f.button :submit, :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
pages_path, :class => 'btn' %>
</div>
</div>
</div>
<div class="span9">
<%= f.simple_fields_for :media do |m| %>
<%= m.input :image, as: :file %>
<% end %>
</div>
<% end %>
<%= render :partial => 'display_images' %>
Please comment if you need any more information or code. All tips, answers or constructive comments are appreciated. :)
this code:
<%= f.simple_fields_for :media do |m| %>
<%= m.input :image, as: :file %>
<% end %>
will only allow you to update the images you already have.
To add more images I suggest you follow this episode of railscast: http://railscasts.com/episodes/196-nested-model-form-revised
I am trying to figure out the whole nested form thing, and am having issues rending the form for editing.
I'm not doing this the "typical way" with a new and create action, because i'm not actually going to be saving anything. I'm just using this form to generate some tests.
Here is what I have..
model.rb
class Model < ActiveRecord::Base
has_many :columns
has_many :associations
accepts_nested_attributes_for :associations, :reject_if => lambda { |a| a[:type].blank? }
accepts_nested_attributes_for :columns, :reject_if => lambda { |a| a[:name].blank? }
attr_accessible :name, :associations_attributes, :columns_attributes
end
column.rb
class Column < ActiveRecord::Base
belongs_to :model
attr_accessible :db_index, :mass_assign, :max_length, :min_length, :name, :required, :unique, :columns_attributes
validates :name, :presence => true
end
generator_controller.rb
def model
if params['submit']
#model = Model.new(params[:model])
#model.columns.build
else
#model = Model.new
3.times { #model.columns.build }
end
render 'generator/model'
end
form view
<%= nested_form_for(#model, :url => '/model', :html => {:style => 'width:100%;'}) do |f| %>
<%= flash_helper() %>
<h3>Model Name</h3>
<%= f.text_field :name %>
<h3>Add Table Columns</h3>
<div id="columns">
<% f.fields_for :columns do |builder| %>
<div class="float_left column">
<%= builder.label :name %>
<br>
<%= builder.text_field :name, :size => 20 %>
</div>
<div class="float_left column">
<%= builder.label :mass_assign %>
<br>
<%= builder.check_box :mass_assign %>
</div>
<div class="float_left column">
<%= builder.label :required %>
<br>
<%= builder.check_box :required %>
</div>
<div class="float_left column">
<%= builder.label :unique %>
<br>
<%= builder.check_box :unique %>
</div>
<div class="float_left column">
<%= builder.label :db_index %>
<br>
<%= builder.check_box :db_index %>
</div>
<div class="float_left column">
<br>
<%= image_tag "delete-icon24x24.png", :class => "btnDel clickable" %>
</div>
<br class="clear_float">
<% end %>
<%= f.link_to_add image_tag('add-icon.png'), :columns %>
</div>
<br><br>
<input type="submit" name="submit">
<p>
<%= #results %>
</p>
<% end %>
So the problem is, the form when new is not displaying the columns that "3.times { #model.columns.build }" is supposed to do. Also, when I submit the form, I need to figure out why it is getting rid of all of those nested attributes that were added. So each time I submit the form, and it renders the form again, all the attributes are gone. (The "model" attributes are still there, but the "column" attributes reset each time)
Any ideas on what i'm doing wrong?
Thanks
I am embarrassed to even admit this, but hopefully it will help someone else with one more thing to check if they have the same problem.
<% f.fields_for :columns do |builder| %>
changed to:
<%= f.fields_for :columns do |builder| %>
Yeah.. can't believe I did that...
I'm trying to create a nested form but i got this error when trying to assign the parameters. I read a bunch of similar posts but cant figure out the problem. What could be wrong?
Can't mass-assign protected attributes: detalle_poliza
My models:
poliza_contable.rb
class PolizaContable < ActiveRecord::Base
has_many :detalle_polizas
accepts_nested_attributes_for :detalle_polizas
attr_accessible :concepto_poliza, :estatus, :fecha_aplicacion, :fecha_poliza, :no_poliza, :tipo, :tota_de_cargos, :total_de_abonos
end
detalle_poliza.rb
class DetallePoliza < ActiveRecord::Base
belongs_to :cuenta_contable
belongs_to :poliza_contable
attr_accessible :abono, :cargo,:cuenta_contable_id, :poliza_contable_id, :user_id, :id, :updated_at, :created_at
end
My form:
<%= form_for #poliza_contable, :html => { :class => 'form-horizontal' } do |f| %>
## OTHER FIELDS
<%= f.fields_for :detalle_poliza_attributes do |builder| %>
<% render :partial => "detalle_polizas/form", :locals => { :f => builder } %>
<% end %>
<% end %>
Rendered form:
<div class="control-group">
<%= f.label :cargo, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :cargo, :class => 'text_field' %>
</div>
</div>
<div class="control-group">
<%= f.label :abono, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :abono, :class => 'text_field' %>
</div>
</div>
<div class="control-group">
<%= f.label :poliza_contable_id, :class => 'control-label' %>
<div class="controls">
<%= f.number_field :poliza_contable_id, :class => 'number_field' %>
</div>
</div>
<div class="control-group">
<%= f.label :cuenta_contable_id, :class => 'control-label' %>
<div class="controls">
<%= f.number_field :cuenta_contable_id, :class => 'number_field' %>
</div>
</div>
<div class="control-group">
<%= f.label :user_id, :class => 'control-label' %>
<div class="controls">
<%= f.number_field :user_id, :class => 'number_field' %>
</div>
</div>
Request Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"mI23Nnj4oPX+IW3mCvvIV7Auij+pjX/a7bl/HsudEW8=",
"poliza_contable"=>{"tipo"=>"Diario",
"concepto_poliza"=>"",
"fecha_poliza"=>"2012-06-25",
"detalle_poliza"=>{"cargo"=>"34",
"abono"=>"34",
"poliza_contable_id"=>"34",
"cuenta_contable_id"=>"34",
"user_id"=>"1"}}
"commit"=>"Create Poliza contable"}`
I'll appreciate any comment to fix it.
With according to railscast 196 Nested Model Form Part 1 you need to allow DetallePoliza attributes to be saved with parent. To achieve this goal just add attr_accessible :detalle_polizas_attributes to PolizaContable model:
poliza_contable.rb
class PolizaContable < ActiveRecord::Base
has_many :detalle_polizas
accepts_nested_attributes_for :detalle_polizas
attr_accessible :concepto_poliza, :estatus, :fecha_aplicacion, :fecha_poliza, :no_poliza, :tipo, :tota_de_cargos, :total_de_abonos, :detalle_polizas_attributes
end
Just making some research, finally found the nestes_form gem
Its a very straight forward implementation!
Hope it helps someone.