I just started learning Rails 4.2. The problem is that one field in the form is not being displayed.
I have restaurant, category and a dish. While creating a dish, the category and restaurant will also be inputted via /dishes/new.
Expected behaviour: Dish, Category and Restaurant fields are displayed.
Actual behaviour: Only Dish and Category fields are displayed.
Here are my models
models/restaurant.rb
class Restaurant < ActiveRecord::Base
has_many :categories
has_many :dishes, :through => :categories
end
models/category.rb
class Category < ActiveRecord::Base
belongs_to :restaurant
has_many :dishes
end
models/dish.rb
class Dish < ActiveRecord::Base
belongs_to :category
validates :name, :price, :category, :restaurant, :presence => true
accepts_nested_attributes_for :restaurant, :category
end
dish controller
def new
# I think this is where
# I am making a mistake
#dish = Dish.new
category = #dish.build_category
restaurant = category.build_restaurant
end
def create
#dish = Dish.new(dish_params)
respond_to do |format|
if #dish.save
.... # default stuff #
end
end
end
# strong params
def dish_params
params.require(:dish).permit(:name, :description, :price, restaurant_attributes: [:name], category_attributes: [:name])
end
Dishes views/dishes/_form.html.erb
<%= form_for(#dish) do |f| %>
<% if #dish.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#dish.errors.count, "error") %> prohibited this dish from being saved:</h2>
<ul>
<% #dish.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :nameWoW %><br>
<%= f.text_area :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :price %><br>
<%= f.number_field :price %>
</div>
*** The restaurant name field is not being displayed **
<%= f.fields_for :restaurant do |restaurant| %>
<div class="field">
<%= restaurant.label :Restname %><br>
<%= restaurant.text_area :name %>
</div>
<% end %>
<%= f.fields_for :category do |category| %>
<div class="field">
<%= category.label :Catname %><br>
<%= category.text_area :name %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I have followed steps from rails guide, browsed questions on stackoverflow and read some blog posts as well but havent been able to figure out whats wrong. Some micro level mistake is blocking me :( . Anyone knows whats wrong ?
Thanks in advance.
UPDATE:
Hey I found a solution.
def new
#dish = Dish.new
#dish.build_category
#dish.category.build_restaurant
end
This works well.But this is just a part of the actual solution. I had to do lot of /dish/create controller modification as well. I think the entire solution will have to be put in blog post. Otherwise it wont make any sense. I will soon be posting and updating it here.
You can add this in your dish.rb
class Dish
delegate :restaurant, to: :category
end
Or you can do
<%= f.fields_for :restaurant, #dish.category.restaurant do |restaurant| %>
<div class="field">
<%= restaurant.label :Restname %><br>
<%= restaurant.text_area :name %>
</div>
<% end %>
I think you are missing:
class Dish
belongs_to :restaurant, through: :category
end
You have it on the other side (many) but not there. You could test this by trying to output #dish.restaurant on your form (should be empty but not nil).
def new
# I think this is where
# I am making a mistake
#dish = Dish.new
category = #dish.category.build
restaurant = category.restuarant.build
end
Related
I was following this RailsCast about Nested Model Form, but something seems weird.
Here is Model relationship
class Question < ActiveRecord::Base
belongs_to :survey
end
class Survey < ActiveRecord::Base
has_many :questions
accepts_nested_attributes_for :questions
end
_form.html.erb(created by scaffold)
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<% f.fields_for :questions do |builder| %>
<div class ='question'>
<%= builder.label :content, "Question" %>
<br>
<%= builder.text_area :content, :rows => 3 %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
survey_controller.rb
# GET /surveys/new
def new
#survey = Survey.new
3.times do |i|
#survey.questions.build
end
end
I was expecting it will display like
However,it didn't display 3 blocks of question.
You've missed a very small but important part of the form - actually outputting the f.fields_for call.
You need to call <%= f.fields_for :question (note the =) to actually output the generated form.
I have two models that I would like to create with one form. I tried following this railscasts tutorial, but I just can't get the nested fields to display on the form. How can I make these nested fields appear?
Models
class Poll < ActiveRecord::Base
has_many :poll_answers, :dependent => :destroy
accepts_nested_attributes_for :poll_answers, allow_destroy: true
end
class PollAnswer < ActiveRecord::Base
belongs_to :poll
end
Controller
class PollsController < ApplicationController
def new
#poll = Poll.new
2.times { #poll.poll_answers.build }
end
private
def poll_params
params.require(:poll).permit([
:question,
poll_answers_attributes: [:answer]
])
end
end
View
<%= form_for(#poll) do |f| %>
<div class="field">
<%= f.label :question %><br>
<%= f.text_field :question %>
</div>
<% f.fields_for :poll_answers do |pa| %>
<p>Hello
<%= pa.text_field :answer %>
</p>
<% end %>
<%= debug #poll.poll_answers %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
You missed an =
<%= f.fields_for :poll_answers do |pa| %>
<p>Hello
<%= pa.text_field :answer %>
</p>
<% end %>
i have 2 models, User and Technician
class User < ActiveRecord::Base
has_one :technician
end
class Technician < ActiveRecord::Base
belongs_to :user
validates :user, presence: true
end
When creating a new Technician and trying to associate with an existing User it gives the error: User cannot be blank
the view of Technician.new (form) is:
<%= form_for(#technician) do |f| %>
<% if #technician.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#technician.errors.count, "error") %> prohibited this technician from being saved:</h2>
<ul>
<% #technician.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :codigo %><br>
<%= f.number_field :codigo %><br><br>
<%= f.label :user_id %><br>
<%= f.select :user_id, options_for_select(User.all.map{|u|[u.nome, u.id]}) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
What am I doing wrong if, selecting an user from the select it won't associate it to the attribute user_id?
Thanks
Try using with collect like this
<%= f.select :user_id, User.all.collect {|u|[u.nome, u.id]}) %>
OR
If you are using Rails 4,you can use pluck
<%= f.select :user_id, User.pluck(:nome, :id))
For more details see this API
If that doesn't work,change your validation in Technician model like this
class Technician < ActiveRecord::Base
belongs_to :user
validates :user_id, presence: true
end
Update
As you are using Rails4,you should be adding user_id to the permitted parameters like this
def your_params
params.require(:technician).permit(:user_id,:codigo)
end
Okay so you can see my models and controller below. What I want to be able to do is when a user is adding a new lease, the user can select from a list of the properties already in the database for the property_id, and also select from a list of the tenants on file for the tenant_id. I am relatively new to rails and really don't have a clue how I would go about doing this. In my controller I put #property = Property.all #tenant = Tenant.all to make them accessible but I don't know how to leverage them in the way that I want.
Lease Model
class Lease < ActiveRecord::Base
attr_accessible :lease_end, :lease_start, :property_id, :tenant_id
belongs_to :tenant
belongs_to :property
end
Property Model
class Property < ActiveRecord::Base
attr_accessible :address_line_1, :city, :county, :image, :rent
belongs_to :lease
end
Tenant Model
class Tenant < ActiveRecord::Base
attr_accessible :email, :name, :phone
belongs_to :lease
end
Lease controller methods for adding a new lease and editing a lease
def new
#lease = Lease.new
#property = Property.all
#tenant = Tenant.all
respond_to do |format|
format.html # new.html.erb
format.json { render json: #lease }
end
end
# GET /leases/1/edit
def edit
#lease = Lease.find(params[:id])
#property = Property.all
#tenant = Tenant.all
end
EDIT:
Drop down box work but the options arn't wahat I want. I am getting options like # for tenants and # for properties. I would like if I could get the tenants names and the address of the properties instead
_form file code updated with teresko's suggestions
<%= form_for(#lease) do |f| %>
<% if #lease.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#lease.errors.count, "error") %> prohibited this lease from
being saved:</h2>
<ul>
<% #lease.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :tenant_id %><br />
<%= f.select :tenant, options_for_select(#tenants) %>
</div>
<div class="field">
<%= f.label :property_id %><br />
<%= f.select :property, options_for_select(#properties) %>
</div>
<div class="field">
<%= f.label :lease_start %><br />
<%= f.date_select :lease_start %>
</div>
<div class="field">
<%= f.label :lease_end %><br />
<%= f.date_select :lease_end %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
First tip : the good practice is to use #properties when you have many properties, not #property. Idem with #tenants.
Then, you can set this in the new or edit page :
<% form_for #lease do |f| %>
<%= f.select :property, options_for_select(#properties) %>
<%= f.select :tenant, options_for_select(#tenants) %>
<% end %>
Next tip is to use a partial named app/views/leases/_form.html.erb to set the previous form, when the new and edit are rendering the same form. Then, your new and edit views will become
<%= render :partial => 'form' %>
To have specific option display, you can read the options_for_select or options_from_collection_for_select docs
http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-options_for_select
<%= f.select :property, options_from_collection_for_select(#properties, 'id', 'name') %>
Choose the best method to your case.
I'm using rails to create a new product and want to add a category to every product.
I have three tables: product, category, and categorizations (which stores the relationship between products and categories). I'm trying to use nested attributes to manage the creation of the categorizations, but unsure how my controller and view/form should be updated so that new products also update the categorizations table.
Here are my models:
class Product < ActiveRecord::Base
belongs_to :users
has_many :categorizations
has_many :categories, :through => :categorizations
has_attached_file :photo
accepts_nested_attributes_for :categorizations, allow_destroy: true
attr_accessible :description, :name, :price, :photo
validates :user_id, presence: true
end
class Category < ActiveRecord::Base
attr_accessible :description, :name, :parent_id
acts_as_tree
has_many :categorizations, dependent: :destroy
has_many :products, :through => :categorizations
end
class Categorization < ActiveRecord::Base
belongs_to :category
belongs_to :product
attr_accessible :category_id, :created_at, :position, :product_id
end
Here is my new product controller:
def new
#product = Product.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #product }
end
end
And here is my view form:
<%= form_for #product, :html => { :multipart => true } do |f| %>
<% if #product.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#product.errors.count, "error") %> prohibited this product from being saved:</h2>
<ul>
<% #product.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br />
<%= f.text_field :description %>
</div>
<div class="field">
<%= f.label :price %><br />
<%= f.number_field :price %>
</div>
<div class="field">
<%= f.file_field :photo %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
How should I update my controller so that both the product and the categorization tables are updated when a new product is added? How do I update my view file so that the categories appear in a drop down menu?
I see that product has_many categories. It's naturally to allow the user to specify them at product creation/edition. One approach is described here (via checkboxes to assign categories to your product). Another way: create product as usually and allow adding/removing categories on its edit page, like:
cat_1 [+]
cat_2 [-]
cat_3 [+]
Also take a look at Railcasts, like this one for doing it on a more beautiful way.
First of all to show categories in view file use something like following to show category in dropdown
<%= select_tag("category_id[]", options_for_select(Category.find(:all).collect { |cat| [cat.category_name, cat.id] }, #product.category.collect { |cat| cat.id}))%>
Then in create method of product controller do something like following
#product = Product.create(params[:category])
#product.category = Category.find(params[:category_id]) if params[:category_id]
I hope this would help you.
Thanks.
Tutorial for Nested Model Form from RailsCasts
Maybe help you, or maybe It will help someone else.
Here is what I addded to my Product view file, in _form.html - this created multiple check boxes that I could use to select multiple categories per product:
</div class="field">
<% Category.all.each do |category| %>
<%= check_box_tag "product[category_ids][]", category.id %>
<%= label_tag dom_id(category), category.name %><br>
<% end %>