Currently I have a has_one relationship betweeen Users and photos.
User model:
has_one :photo
accepts_nested_attributes_for :photo
Photo model:
belongs_to :user
Paperclip.options[:command_path] = "/usr/local/bin"
has_attached_file :image,
:path => ':rails_root/public/images/ads/:id/:basename.:extension',
:url => "images/ads/:id/:basename.:extension"
The nested form:
<%= f.simple_fields_for :photo_attributes, :html => { :multipart => true } do |d| %>
<%= d.input :billed_navn %>
<%= d.label :image, :label => 'Upload logo', :required => false %>
<%= d.file_field :image, :label => 'Image', :class => 'imagec', :required => 'false', :style => 'margin-bottom:2px;float:left;width:250px;' %>
<input type="button" value="Clear" id="clear" style="width:70px;float:left;margin-right:2px;">
<%= d.input :image_url, :label => 'Billed URL', :input_html => { :class => 'imagec'}, :required => false %>
<%= f.label :image, :label => 'Billed preview', :required => false %><div id="preview"></div>
<% end %>
This setup works as it should, I can upload 1 photo.
I users to be able to upload multiple photos at once.
Therefor I have changed the assocition in useres model to:
User model:
has_many :photos
accepts_nested_attributes_for :photos
But I how should the nested form then be? If it should be possible to upload mulitple images at once?
The accepts_nested_attributes_for thing only allows mass assignment to add multiple photos at once. (Beware of mass assignment security vulnerabilities! strong_parameters gem recommended). This means that the update action accepts multiple photos.
It will only add it if they are sent, which happens if there are fields in the form that a user fills out. This is mainly determined by the edit view.
Because you don't know how many photos a user will want to add, the best way to do this is to use javascript to dynamically add an extra set of fields for a photo when requested by the user. This can be a link, which when clicked, appends the fields to the form. This way the user can submit as many photos at once as they want.
You will also want to have some validation so that if a set of empty fields (for a photo) are submitted, it doesn't add a non-photo photo.
If you don't want to use javascript, the best you can do is to just assume the user will upload at most say 3 at a time, and include 3 sets of photo fields. Again, being careful to deal with empty fields appropriately.
Example:
<% (1..5).each do |I| %>
<%= fields_for "user[photo_attributes][]", nil, :index => I do |form| %>
<%= form.input :billed_navn %>
...
<% end %>
<% end %>
Related
Sorry for long post, usually don't post here often.
Rails 3.1
I have a Company model. Company has many custom properties. All properties names are standardized (e.g. company size, company revenue, etc). Some property values are custom and some are "standartized" (relation to another table CompanyProperty - property_value_id).
What I am trying to do is a form where new Company Properties are added. In a form I try to add different properties at once. Everything works except I cannot figure out how to add multiple values via collection_select.
Here are models:
Company:
has_many :properties, :class_name => 'CompanyProperty'
CompanyProperty:
belongs_to :company
belongs_to :property, :class_name => 'Property'
belongs_to :property_value, :class_name => 'PropertyValue', :foreign_key => 'properties_value_id'
Property:
has_many :company_properties
has_many :property_values
PropertyValue:
belongs_to :properties
has_many :company_properties
Form (marked comment # problem where using collection_select with multiple selection):
<%= form_for(#company, :url => {:action => 'update_company', :id => #company.id}, :html => {:multipart => true}) do |f| %>
<% #company.properties.each.with_index do |p,i| %>
<%= f.fields_for :properties, p do |builder| %>
<%= p.property.title %><br />
<% if p.property.standard == 0 %>
<%= builder.hidden_field :property_id %>
<%= builder.text_field :value %> <br />
<% elsif p.property.standard == 1 %>
<%= builder.hidden_field :property_id %>
<%= builder.collection_select(:properties_value_id, p.property.property_values, :id, :text_value, {:include_blank => true},
{:class => 'form-control'}) %>
# Problem:
<% elsif p.property.standard == 2 %>
<%= builder.hidden_field :property_id %>
<%= builder.collection_select(:properties_value_id, p.property.property_values, :id, :text_value, {:include_blank => false},
{:multiple => true, :size => p.property.property_values.count, :class => 'form-control'}) %>
<% end %>
<% end %>
<% end %>
<%= submit_tag("Save", :class => "btn btn-primary btn-block") %>
<% end %>
Controller:
def update_company
#company = Company.find(params[:id])
if #company.update_attributes(params[:company])
render :text => "Saved"
else
error = #company.errors.full_messages.map{|o| "<li>" + o + "</li>" }.join("") + "</ul>"
render :text => error
end
end
All property_id and values are saved, except values from collection_select with multiple selection. The post parameters goes something like this (4 records created, expected result - 6 new records):
Parameters: {"company"=>{"properties_attributes"=>{"0"=>{"property_id"=>"1", "properties_value_id"=>"2"}, "1"=>{"property_id"=>"2", "value"=>"34"},
"2"=>{"property_id"=>"3", "properties_value_id"=>["", "4", "5", "6"]},
"3"=>{"property_id"=>"4", "value"=>"34"}}}, "commit"=>"Save", "id"=>"16"}
property_id=>3 is that particular property that I'm trying to save. Expected result is to see three new records on CompanyProperties table with property_id = 3 and values properties_value_id accordingly. But this does not happens. Only one records is being created with property_id=3 and the properties_value_id is 1 (why?, there is no such value).
Plus I cannot understand why there is blank param here "properties_value_id"=>["", "4", "5", "6"]}. There are no such value :/
Could any one help to reach my expected result?
This should be a comment, but I'll post here to keep it readable:
The blank param will likely be a "selector" / "default" value in your select box. Failing that, is there any way you can see how your HTML element may be including a separate element in the property_value_ids?
If you were using Rails 4, I'd recommend your strong params were incorrect - however, as you're using Rails 3, I'd surmise you should do something like this:
<%= builder.collection_select("properties_value_id[]", p.property.property_values, :id, :text_value, {:include_blank => false},
{:multiple => true, :size => p.property.property_values.count, :class => 'form-control'}) %>
This question already has an answer here:
Rails -- how to populate parent object id using nested attributes for child object and strong parameters?
(1 answer)
Closed 6 years ago.
I'm trying to build a nested form that will create a new user and subscribe them to a plan.
When I hit "Enroll" I get the following error:
Validation failed: Plan subscriptions user can't be blank
I've double and triple checked everything below and am not sure what's wrong at this point. Any idea why the subscription is not being associated to the new user record?
Here's my code:
User.rb
class User < ActiveRecord::Base
attr_accessible ..., :plan_subscriptions_attributes
has_many :plan_subscriptions, dependent: :destroy
accepts_nested_attributes_for :plan_subscriptions
PlanSubscriptions.rb
class PlanSubscription < ActiveRecord::Base
belongs_to :user
Plan_Subscriptions#new
def new
#plan = Plan.find(params[:plan_id])
#user = User.new
#user.plan_subscriptions.build
end
Plan_Subscriptions/New.html
<%= form_for #user do |f| %>
<fieldset>
<%= f.text_field :first_name, :label => false, :placeholder => 'First Name', :required => false %>
<%= f.text_field :last_name, :label => false, :placeholder => 'Last Name',
<%= f.fields_for :plan_subscriptions do |builder| %>
<%= builder.hidden_field :plan_id, :value => #plan.id %>
<% end %>
<%= f.submit 'Enroll', :error => false %>
</fieldset>
<% end %>
Plan wont have an id at this point in the execution so I wouldn't use that. Try removing the line:
<%= builder.hidden_field :plan_id, :value => #plan.id %>
#plan.id will be nil, so it will overwrite the automatically built object and thus fail the validation.
Then attempt to submit the form again. Try adding a valid form element for the plan subscription if you want the user to set something in the subscription.
So I'm having an issue setting a primary image for my Dress object via a form.
The form allows the user to edit the dress details and then add/remove images to the form (using nested_form) and for each of them set a label and assign a primary image.
Everything works so far except for setting the primary image via radio buttons.
Dress Model:
class Dress < ActiveRecord::Base
has_many :dress_images
has_one :primary_dress_image, :class_name => "DressImage", :conditions => { :is_primary => true }
accepts_nested_attributes_for :dress_images, :allow_destroy => true
validates :name, :presence => true, :length => { :maximum => 99 }
end
DressImage Model
class DressImage < ActiveRecord::Base
belongs_to :dress
# Same as:
# def self.primary
# where(:is_primary => true)
# end
scope :primary, where(:is_primary => true)
# clear old primary if:
# this is a new record
# this is existing and is_primary has been set to true
before_save :clear_primary,
:if => Proc.new{ |r| (r.new_record? && r.is_primary) || (r.is_primary_changed? && r.is_primary) }
validates :label, :presence => true, :length => { :maximum => 60 }
validates :caption, :length => { :maximum => 200 }
mount_uploader :image, ImageUploader
def clear_primary
DressImage.update_all( {:is_primary => false}, :dress_id => self.dress_id )
end
end
Dress edit form
<h1>Dress</h1>
<% #dress.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %> <%#= f.label :name %>
<%= nested_form_for #dress, :as => :dress, :url => { :action => :update }, :html=>{ :multipart => true } do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :description %>
<%= f.text_area :description %>
<%= f.fields_for :dress_images do |dress_image_form| %>
<div class="dress-image">
<%= image_tag dress_image_form.object.image_url(:thumb) %>
<%= dress_image_form.text_field :label %>
<%= dress_image_form.file_field :image %>
<div class="primary-image-radio">
<%= dress_image_form.label :is_primary, "Main Image" %>
<%= f.radio_button :primary_dress_image_id, dress_image_form.object.id %>
</div>
<p>
<%= dress_image_form.link_to_remove "Remove this attachment" %>
</p>
</div>
<% end %>
<%= f.link_to_add "Add Photo", :dress_images %>
<%= f.submit "Save Dress" %>
<% end %>
With this radio button, the primary_dress_image_id attribute is set on the Dress object, but #dress.primary_dress_image gives a different result to the ID.
If I change the radio button to <%= dress_image_form.radio_button :is_primary, true %> it works better but because the name of each radio button is different, they are not treated as the same group.
I'm new to rails so I might be missing something completely obvious or doing it all wrong.
Here's one solution.
Add a hidden input to each of your nested field groups. Use a radio_button_tag instead of radio_button to make sure they are in the same group:
<div class="dress-image">
<%= dress_image_form.hidden_field :is_primary, :class => 'primary-image' %>
...
<%= radio_button_tag "select_primary_image", true, dress_image_form.object.is_primary? %>
...
</div>
Then add some javascript to update the hidden field according to the radio button selection:
$("body").on "change", ".primary-image-radio input:radio" ->
$(#).closest(".dress-image").find(".primary-image").val( $(#).is(":checked") )
You might need to modify the code a little because it's just an untested quick example, but it should give you an idea.
So I ended up using this method: <%= dress_image_form.radio_button :is_primary, true %> and using jquery to deselect all the other radio buttons when one is clicked.
This seems like a bit of a hacky method to me - there must be a purely Rails way of doing this without having to resort to JS? Until I find a better one, I'm going to stick with this solution.
I'm trying to display the recent scores of a team from a database based on the selection from a collection_select drop down. I know that I need to listen for the change event on the drop down but I don't know how to do the AJAX request or how to display the data in the view.
Ok, I will write a example with category and subcategory models.
The first is relation between models:
class Category
has_many :subcategories
has_many :objects
end
class Subcategory
belongs_to :category
has_many :objects
end
class Object
belongs_to :category
belongs_to :subcategory
end
Now the form on view, for example with simple_form gem (you can do it with form_for):
<%= simple_form_for(#object, :html => {:multipart => true }) do |f| %>
<%= f.input :category, :collection => Category.all :prompt => "Select Category" %>
<%= f.input :subcategory, :label_html => { :class => 'subcategory_label_class' } do %>
<%= f.grouped_collection_select :subcategory_id, Category.order_by(:title), :subcategories, :title, :id, :name, include_blank: true %>
<% end %>
<%= f.button :submit %>
<% end %>
With this we grouped the subcategories with their parent category.
The next step you must add the code to your objects.js.coffee
$('#object_subcategory_id').parent().hide()
subcategories = $('#object_subcategory_id').html()
$('#object_category').change ->
category = $('#object_category :selected').text()
escaped_category = category.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/#])/g, '\\$1')
options = $(subcategories).filter("optgroup[label='#{escaped_category}']").html()
if options
$('#object_subcategory_id').html(options)
$('.subcategory_label_class').show()
$('#object_subcategory_id').parent().show()
else
$('#object_subcategory_id').empty()
$('.subcategory_label_class').hide()
$('#object_subcategory_id').parent().hide()
You can adapt this example to your needs.
I hope it helps.
Regards!
you need to build a separate controller and send the ajax request when your change event is triggered, the controller sends back a js response, that you have to handle in your clients javascript... the following link should give you an example http://blog.bernatfarrero.com/jquery-and-rails-3-mini-tutorial/
I can't figure out, or find any solutions to a very simple question:
"How can I define my own input field in formtastic?"
This is what I got:
<%= semantic_form_for #someFantasticVariable, :url => "/someFantasticUrl.html" do |f|%>
<%= f.inputs do %>
<%= f.input :something_else_id, :required => true , :as => :select, :collection => SomethingElse.find(:all), :label =>"The something else"%>
<%= f.input :fantastic_max_cost, :label => "Budget (max cost)"%>
<%end%>
<%= f.buttons do%>
<%= f.commit_button :button_html => { :class => "primary", :disable_with => 'Processing...', :id => "commitButton"}%>
<%end%>
<%end%>
Now..
I want to have a very simple thing. I want to ad a field that is not part of the model. I want to have a date field that I can use to calculate some stuff in my controller. So I want to do this:
<%= f.inputs do %>
<%= f.input :something_else_id, :required => true , :as => :select, :collection => SomethingElse.find(:all), :label =>"The something else"%>
<%= f.input :fantastic_max_cost, :label => "Budget (max cost)"%>
<%= f.input :start_date, :as => :date , :label => "Start date"%>
<%end%>
But apparetly I'm not allowed, and I can't find any way to do this through my thrusted googling. Any help / ideas?
If you have some attribute that is not part of your model, then a getter and a setter should exist on the model:
def start_date
end
def start_date=(arg)
end
Then you can calculate your staff on a controller or whatever you want:
...
puts params[:somefantasticvariable][:start_date]
...
But this is a quick formtastic hack, you should find some better way, like non-formtastic input with some css etc.
Ruby provides a database-less construct called an attr_accessor. It is the equivalent of writing setter and getter methods. Formtastic will see this attribute similar to a database-backed attribute.
In your #someFantasticVariable model:
attr_accessor :start_date
If using attr_accessible in your #someFantasticVariable model, be sure to add the start_date variable there too:
attr_accessible :start_date
Because the attribute is type-less, Formtastic cannot derive the HTML input field to use. You will need to manually set the input type using :as. For your example:
<%= f.input :start_date, :as => :date_select %>
Cite:
http://apidock.com/ruby/Module/attr_accessor
https://github.com/justinfrench/formtastic#the-available-inputs