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
Related
I have 2 models:
class Page < ApplicationRecord
enum page_type: STATIC_PAGE_TYPES, _suffix: true
has_one :seo_setting
accepts_nested_attributes_for :seo_setting, update_only: true
validates :title, :subtitle, length: { maximum: 50 }
validates :page_type, uniqueness: true
def to_param
"#{id}-#{page_type}".parameterize
end
end
and
class SeoSetting < ApplicationRecord
mount_uploader :og_image, SeoSettingsOgImageUploader
belongs_to :page
validates :seo_title, :seo_description, :og_title, :og_description, :og_image, presence: true
end
My Page objects are created from the seeds.rb file, and when I want to edit them, I get an error: Failed to save the new associated seo_setting.
In the form I have this:
<div class="card-body">
<%= form_for([:admin, #page]) do |f| %>
<%= render 'shared/admin/error-messages', object: #page %>
<div class="form-group">
<%= f.label :title, t('admin.shared.title') %>
<%= f.text_field :title, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :subtitle, t('admin.shared.subtitle') %>
<%= f.text_field :subtitle, class: 'form-control' %>
</div>
<h3>SEO Settings</h3>
<%= f.fields_for :seo_setting, f.object.seo_setting ||= f.object.build_seo_setting do |form| %>
<div class="form-group">
<%= form.label :seo_title, t('admin.shared.seo_title') %>
<%= form.text_field :seo_title, class: 'form-control' %>
</div>
<div class="form-group">
<%= form.label :seo_description, t('admin.shared.seo_description') %>
<%= form.text_area :seo_description, class: 'form-control' %>
</div>
<div class="form-group">
<%= form.label :og_title, t('admin.shared.og_title') %>
<%= form.text_field :og_title, class: 'form-control' %>
</div>
<div class="form-group">
<%= form.label :og_description, t('admin.shared.og_description') %>
<%= form.text_area :og_description, class: 'form-control' %>
</div>
<div class="form-group">
<%= form.label :og_image, t('admin.shared.og_image') %>
<div class="row">
<div class="col-lg-12">
<%= image_tag(form.object.og_image.url, style: 'width: 100px') if form.object.og_image? %>
</div>
</div>
<%= form.file_field :og_image %>
<%= form.hidden_field :og_image_cache %>
</div>
<% end %>
<div class="form-group">
<%= f.submit t('admin.actions.submit'), class: 'btn btn-success' %>
<%= link_to t('admin.actions.cancel'), admin_page_path(#page) , class: 'btn btn-default' %>
</div>
<% end %>
</div>
If I remove validations from my SeoSetting model, everything is working. It seems Rails doesn't like this part: f.object.build_seo_setting, because it creates a record in my database. Any ideas of how can I solve this issue? Thanks ahead.
Just had to change this line:
<%= f.fields_for :seo_setting, f.object.seo_setting ||= f.object.build_seo_setting do |form| %>
for this one:
<%= f.fields_for :seo_setting, #page.seo_setting.nil? ? #page.build_seo_setting : #page.seo_setting do |form| %>
Looks as if the problem lies here:
accepts_nested_attributes_for :seo_setting, update_only: true
in that you only allow the updating of the seo_setting on update.
Then, when you use this code:
f.object.seo_setting ||= f.object.build_seo_setting
You're falling back to a new seo_setting if the associated object is missing.
For this to work, you'll need to either remove the update_only: true, or only render the fields for the association if the seo_setting already exists.
Accepted answer, a conditional inside fields_for line, by OP, works also with polymorphic association and nested form (fields_for). Thnx Alex.
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 form_for select where the options are being defined from within the model. I am trying to get it to display a placeholder option but cannot figure out how to.
The Model:
class Factoid < ActiveRecord::Base
attr_accessible :description, :name, :title
validates_presence_of :description, :name, :title
validates_uniqueness_of :title
NAMES = "Angela", "Geordie", "Jared", "Jennifer", "Kevin", "Matthew", "Oscar", "Owen", "Regina", "Todd", "Vaibhavi", "Zack"
UNRANSACKABLE_ATTRIBUTES = ["id", "updated_at"]
def self.ransackable_attributes auth_object = nil
(column_names - UNRANSACKABLE_ATTRIBUTES) + _ransackers.keys
end
end
The Form:
<%= form_for #factoid, :html => { :class => 'form-horizontal' } do |f| %>
<div class="control-group">
<%= f.label :title, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :title, :class => 'text_field' %>
</div>
</div>
<div class="control-group">
<%= f.label :description, :class => 'control-label' %>
<div class="controls">
<%= f.text_area :description, :class => 'text_area' %>
</div>
</div>
<div class="control-group">
<%= f.label :name, :class => 'control-label' %>
<div class="controls">
<%= f.select :name, :collection => Factoid::NAMES %>
</div>
</div>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
factoids_path, :class => 'btn' %>
</div>
<% end %>
The second issue is that the dropdown menu is displaying the word "collection" at the top of it (See screenshot below). How do I get read of that. Ideally I want to have a dropdown menu with a placeholder of "Names" that is also displayed at the top when the dropdown menu is opened.
For your text field try something like:
<%= f.text_field :title, :class => 'text_field', value: 'my_default_value' %>
for your select try:
<%= f.select :name, Factoid::NAMES %>
See the docs for select and the rails guide for typical usage (I think the method I've shown you will not work upon submitting the form, see the guides linked for explanation, I'm not sure though).
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.