Im looking for the proper way to build a form for the following data structure:
class Profile < ActiveRecord::Base
attr_accessible :name
has_many :weights
accepts_nested_attributes_for :weights
end
class Tag < ActiveRecord::Base
attr_accessible :name
has_many :weights
end
class Weight < ActiveRecord::Base
attr_accessible :weight, :profile_id, :tag_id
belongs_to :profile
belongs_to :tag
end
In the edit profile form I want to pull in all the weights and allow users to update them. I've been able to do this with nested attributes like so:
<%= form_for [:admin, #profile] do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :name %>
<%= f.text_field :name %>
</p>
<div class='weights'>
<%= f.fields_for :weights do |ff| %>
<%= ff.label :weight %>
<%= ff.text_field :weight %>
<% end %>
</div>
<%= f.submit %>
<% end %>
The thing is that I actually want to pull in the title of the associated tag_id on each weights row as well (so people know which weight's tag they are changing). I don't see a way to pull this info in, should I be doing some sort of join before I write this form out? Is this a silly approach?
Thanks everyone
-Neil
You should be able to get at the weight through ff.object and tag through ff.object.tag.title. Have you tried this?
Related
If a user has_many skills, and a skill belongs_to a user:
class User < ApplicationRecord
has_many :skills
validates_length_of :skills, maximum: 5
end
class Skill < ApplicationRecord
belongs_to :user
validates_associated :user
end
how can a form be made that accepts the user and multiple skills?
Here is a form with the user and one skill, but I can't work out how to make it accept multiple skills in the same form?
<%= form_for(#user) do |f| %>
<%= f.label :bio %><br>
<%= f.text_field :bio %>
<%= fields_for "user[skill]", #user.skill do |skill_fields| %>
<%= f.label :skill %><br>
<%= skill_fields.text_field :name %>
<% end %>
<%= f.submit "Apply", class: "btn btn-primary" %>
<% end %>
Note, it's fine for the (5) fields to be on screen rather than generated dynamically with javascript.
accepts_nested_attributes_for
You can consider using Rails built-in accepts_nested_attributes_for.
Please, have a look at the Active Record Nested Attributes docs, especially in the One-to-many section.
And this is the official guide on how to generate a Rails form for the accepts_nested_attributes_for - 10 Building Complex Forms.
I'm having trouble setting up my associations. I'm trying to set up Courses to have different Prices depending on the Season and amount of alumns. It gets even more complicated when Seasons have different date ranges for the same Season, like for instance the first Season is from 12/24/2014 to 12/31/2014 but also from 01/07/2015 to 01/14/2015. For this I created another model Season_dates.
I can't figure out how to set up my associations, here's what I have got so far:
class Season < ActiveRecord::Base
has_many :season_dates
has_many :prices, through: :season_dates
end
class SeasonDate < ActiveRecord::Base
belongs_to :price
belongs_to :seasons
end
class Price < ActiveRecord::Base
belongs_to :course
has_many :season_dates
has_many :seasons, through: :season_dates
accepts_nested_attributes_for :season_dates
end
class Course < ActiveRecord::Base
has_many :prices
end
Form:
<%= form_for #price do |f| %>
<div class="field">
<%= f.fields_for :couse do |course_f| %>
<%= course_f.label :course %><br>
<%= course_f.collection_select :course_id, Course.all, :id, :name, {}, {class: 'form-control'} %>
<% end %>
</div>
<div class="field">
<%= f.label :alumn %><br>
<%= f.number_field :alumn, in: 1...11, step: 1, class: 'form-control' %>
</div>
<div class="field">
<%= f.fields_for :season_date do |season_f| %>
<%= season_f.label :season %><br>
<%= season_f.select :season_id, options_from_collection_for_select(Season.all, :id, :name), {}, {class: 'form-control'} %>
<% end %>
</div>
<div class="field form-group">
<%= f.label :price %><br>
<%= f.number_field :price, in: 0.01..999.99, step: 0.01, placeholder: "0.00€", class: 'form-control' %>
</div>
<div class="actions">
<%= f.submit class: 'btn btn-default' %>
</div>
<% end %>
I want to be able to call price.season.name or price.course.name. I'm not sure how to proceed, any help is appreciated.
I think you might be complicating the scenario a bit. Is there a reason that SeasonDate is its own class? Is there a way you can model like this?
class Season < ActiveRecord::Base
has_many :courses
# I would have on this model the attributes of from_date and
# to_date removing the need for a SeasonDate class
end
class Course < ActiveRecord::Base
belongs_to :season
# You might need to model this as a has_and_belongs_to_many relationship
# with a Season if a Course can belong to many seasons
end
class Price < ActiveRecord::Base
belongs_to :course
belongs_to :season
end
These models would give you methods such as:
#season.courses # would return all courses in a particular season
#price.season.name
#price.course.name
#course.prices # would return all prices associated with a particular course
If you do go for the habtm association, meaning a course can belong to many seasons, you could do something like this (guessing at your price attribute names) in your views.
<%= #course.name %>
<% #course.prices.each do |price| %>
<%= price.season.name %> : <%= price.price_in_dollars %>
<% end
This would allow you to iterate over all prices for a course and display which season they are applicable for so each person can find the best price for them.
I've being following the rails getting started tutorial and have been changing the model to help my understading of rails.
I have an article model which has_many comments:
class Article < ActiveRecord::Base
has_many :comments, dependent: :destroy
validates :title, presence: true,
length: { minimum: 5 }
end
class Comment < ActiveRecord::Base
belongs_to :article
end
routes.rb
resources :articles do
resources :comments
end
The view to create the comment is in a partial (as per the rails tutorial)
<%= form_for([#article, #article.comments.build]) do |f| %>
<p>
<%= f.label :commenter %><br>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :body %><br>
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
This works fine but I wanted to split this out a bit to make a commenter a separate model (I know its not great OO but I just experimenting here!)
I therefore created a Commenter model:
class Commenter < ActiveRecord::Base
belongs_to :comment
end
changed the Comment to :
class Comment < ActiveRecord::Base
has_one :commenter
belongs_to :article
end
routes.rb
resources :commenters
resources :articles do
resources :comments
end
resources :comments do
resource :commenter
end
I'd like to create the Comment and the commenter at the same time in a single form but I'm stuck on how to change the view to achieve this as the view builds the comments model, do I also need to build the commenter model here? if so how do I achieve this?
<%= form_for([#article, #article.comments.build]) do |f| %>
<p>
<%= f.label :commenter %><br>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :body %><br>
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
For what your looking to do, you need to implement Nested Forms.
From the code you have provided, below I have shown how I would change it.
Models
class Article < ActiveRecord::Base
has_many :comments, dependent: :destroy
accepts_nested_attributes_for :comments # This is required for #article to save the forms nested within it
validates :title, presence: true,
length: { minimum: 5 }
end
class Comment < ActiveRecord::Base
belongs_to :article
accepts_nested_attributes_for :commenter # Required to save nested Commenter form
end
class Commenter < ActiveRecord::Base
belongs_to :comment
end
Article Controller
In the action that will be called when someone decides to comment on an article, you will need to select the #article and create a comment and also a commenter for the comment. These have to be created before the form is rendered, otherwise they won't be displayed.
def create_comment
#article.find(:id_of_article)
#comment = #article.comments.find(:id_of_new_comment)
#comment.create_commenter
end
View
Finally the form
<%= form_for(#article) do |f| %>
<%= f.fields_for(:comments, #comment) do |comment| %> # As article will have many comments, you need to specify the new comment you want to display
<%= comment.label :comment %><br>
<%= comment.text_field :comment %>
<%= comment.fields_for(:commenter) do |commenter| %>
<%= commenter.label :commenter_name %>
<%= commenter.text_field :commenter_name %>
<%end%>
<%end%>
<%= f.submit %>
<% end %>
Anyway, I hope this helps. Although if you're still doing your tutorials, you should learn this fairly soon anyway.
I have a polymorphic model and want to have a nested form use this model. I am getting no errors but the form is not displaying the nested field. Here are my models and stripped down form:
Polymorphic Model
class SeoMapping < ActiveRecord::Base
belongs_to :mappingtable, :polymorphic => true
attr_accessible :seo_url
validates :seo_url, :presence => true, :uniqueness => true
end
Page model using the Polymorphic Model
class Page < ActiveRecord::Base
has_one :seo_mappings, :as => :mappingtable, :dependent => :destroy
accepts_nested_attributes_for :seo_mappings
attr_accessible :content, :h1, :meta_description, :title, :seo_mappings_attributes
.........
end
Now stripped down form
<%= form_for(#page) do |f| %>
<% if #page.errors.any? %>
.......
<% end %>
<div class="field">
<%= f.fields_for :seo_mappings do |builder| %>
<%= builder.label :seo_url %><br />
<%= builder.text_field :seo_url %>
<% end %>
</div>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
.........
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I cant see why it does not display the fields_for elements. If I comment out accepts_nested_attributes_for the field then displays. Can you see where I am going wrong ?
TY
Possibly a silly question but is this the create or edit action you're talking about? And if it's create, did you call #page.build_seo_mapping or something in the controller?
Also (may be unrelated) if you use has_one, usually you want to use a singular noun, so has_one :seo_mapping instead of mappings.
I am having some issues with nested models in a form, using Rails 3.1rc4.
I presently have models that look like this:
class Sale < ActiveRecord::Base
attr_accessible :customer_id, :vehicle_id, :sale_date
belongs_to :customer
accepts_nested_attributes_for :customer
end
and
class Customer < ActiveRecord::Base
attr_accessible :dealership_id, :first_name, :last_name, :address1, :email
belongs_to :dealership
has_many :sales
has_many :vehicles, :through => :sales
end
I've obviously truncated these slightly, but all the important info is there.
I am attempting to set up a sale form that will also allow me to create a new customer, hence the accepts_nested_attributes_for :customer line in the sale model.
My form view looks like (again truncated, only the important part):
<%= form_for #sale, :html => {:class => 'fullform'} do |f| %>
<%= f.error_messages %>
<%= field_set_tag 'Customer Details' do %>
<% f.fields_for :customer do |builder| %>
<%= builder.label :first_name %><br>
<%= builder.text_field :first_name %>
<% end %>
<% end %>
<% end %>
The problem I am having is that neither the text field nor the label for :first_name are showing up when the form is rendered - there is no error message, it just doesn't appear.
I should mention that I have tried both with and without #sale.customer.build in the new method of my controller, but it seems to have had no effect.
Thanks!
Can anyone suggest what I am doing wrong?
EDIT: For the avoidance of doubt, my sales controller's new method looks like:
def new
#sale = Sale.new
#sale.customer.build
end
Add customer_attributes to your attr_accessible in the Sale model.
Another mistake; Replace:
<% f.fields_for :customer do |builder| %>
With:
<%= f.fields_for :customer do |builder| %>