i´m a newbie to rails and have a problem with my associated object not being saved. I think I did everything the way it should be done and I can´t figure out, why it isn´t working. So thanks in advance for everyone who can help me get a little closer to solving this problem.
These are my models :
class Examdate < ActiveRecord::Base
belongs_to :exam
attr_accessible :date, :exam_id
end
class Exam < ActiveRecord::Base
attr_accessible :title, :prof_id, :deadline
belongs_to :prof
has_many :examdates, :dependent => :destroy
accepts_nested_attributes_for :examdates
end
In my exams_controller I have this:
def new
#exam = Exam.new
3.times{#exam.examdates.build()}
end
def create
#exam = Exam.new(params[:exam])
respond_to do |format|
if #exam.save
....
Now in my view I have the semantic_fields_for method, I also tried it with normal fields_for and got the same result:
<%= semantic_form_for #exam do |f| %>
<% if #exam.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#exam.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #exam.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.inputs do%>
<%= f.input :title%>
<%= f.input :prof%>
<%= f.input :deadline, :start_year => Time.now.year, :label => "Anmeldefrist"%>
<% end %>
<%= f.semantic_fields_for :examdates do |builder|%>
<%= render "examdates_fields", :f => builder %>
<% end %>
<%= f.buttons do %>
<%= f.commit_button "Speichern"%>
<% end %>
<% end %>
In the partial is this, will later be extended
<%= f.inputs :date%>
Now I get the form with the correct three date fields and I can save the Exam itself correctly. When I look at params[:exam][:examdates_attributes] the dates are there:
{"0"=>{"date(1i)"=>"2006", "date(2i)"=>"1", "date(3i)"=>"1"},
"1"=>{"date(1i)"=>"2006", "date(2i)"=>"1", "date(3i)"=>"1"},
"2"=>{"date(1i)"=>"2006", "date(2i)"=>"1", "date(3i)"=>"1"}}
But when I put Exam.find(1).exdates in my rails Console, I get []. I really don´t have any idea what I did wrong, so every little tip is very appreciated:)
Since you are using attr_accessible in your Exam model, I think you'll have to include :examdates_attributes in that list. Otherwise, mass assignment to the nested model will not be allowed.
class Exam < ActiveRecord::Base
attr_accessible :title, :prof_id, :deadline, :examdates_attributes
...
Related
I am new to RoR (using rails 5) and have problems with a has_many through: association.
I want to create Categories with different labels for different Languages.
Here is my model:
class Language < ApplicationRecord
has_many :category_infos
has_many :categories, through: :category_infos
end
class Category < ApplicationRecord
has_many :category_infos
has_many :languages, through: :category_infos
accepts_nested_attributes_for :category_infos
end
class CategoryInfo < ApplicationRecord
belongs_to :language
belongs_to :category
accepts_nested_attributes_for :language
end
The controller:
class CategoriesController < ApplicationController
def new
#category = Category.new
#languages = Language.all
#languages.each do |language|
#category.category_infos.new(language:language)
end
end
def create
#category = Category.new(category_params)
if #category.save
redirect_to #category
else
render 'new'
end
end
private
def category_params
params.require(:category).permit(:name, category_infos_attributes:[:label, language_attributes: [:id, :language]])
end
end
The form:
<%= form_with model: #category, local: true do |form| %>
<% if #category.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#category.errors.count, "error") %>:
</h2>
<ul>
<% #category.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<br/>
<% end %>
<p>
<%= form.label :name %>
<%= form.text_field :name %>
</p>
<p>
Labels:
</p>
<table>
<% #category.category_infos.each do |category_info| %>
<tr>
<td>
<%= category_info.language.name %>
</td>
<td>
<%= form.fields_for :category_infos, category_info do |category_info_form| %>
<%= category_info_form.fields_for :language, category_info.language do |language_form| %>
<%= language_form.hidden_field :id, value: category_info.language.id %>
<%= language_form.hidden_field :name, value: category_info.language.name %>
<% end %>
<%= category_info_form.text_field :label %>
<% end %>
</td>
</tr>
<% end %>
</table>
<p>
<%= form.submit %>
</p>
<% end %>
When I create a new category, I get this error :
Couldn't find Language with ID=1 for CategoryInfo with ID=
on Line :
#category = Category.new(category_params)
However I already have registered several languages in database (1 = English, 2 = French etc...)
How do I need to write the form so that I can create a Category and its CategoryInfos in English, French etc... at the same time?
Thanks in advance for your answers
You're making a classic newbie misstake and using fields_for when you just want to create an association by passing an id.
<%= form_with model: #category, local: true do |f| %>
# ...
<%= f.fields_for :category_infos do |cif| %>
<%= cif.collection_select(:language_id, Language.all, :name, :id) %>
<%= cif.text_field :label %>
<% end %>
<% end %>
While you could also pass the attributes to let a users create languages at the same time its very much an anti-pattern as it adds a crazy amount of responsibilities to a single controller. It will also create an authorization problem if the user is allowed to create categories but not languages.
Use ajax to send requests to a seperate languages controller instead if you need the feature.
I'm going off by the tutorial that's in the cocoon gem. When trying to create a Toilet the facilities that I'm adding won't save unless the Toilet is created first. I was thinking that it should have been created together as is. Is there a way to save the facilities when creating the toilet?
To not get things confused
class Toilet < ApplicationRecord
has_many :facilities
accepts_nested_attributes_for :facilities, reject_if: :all_blank, allow_destroy: true
end
class Facility < ApplicationRecord
belongs_to :toilet
end
Toilet controller
def new
#toilet = Toilet.new
end
def create
#toilet = Toilet.new(toilet_params)
if #toilet.save
redirect_to #toilet
else
render :new
end
end
private
def toilet_params
params.require(:toilet).permit(:name, :location, facilities_attributes: [:id, :name, :_destroy])
end
_form.html.erb
<%= f.simple_fields_for :facilities do |facility| %>
<%= render 'facility_fields', :f => facility %>
<% end %>
<div class='links'>
<%= link_to_add_association 'add facility', f, :facilities %>
</div>
<%= f.submit 'Save' %>
<% end %>
_facility_fields.html.erb
<div class='nested-fields'>
<%= f.inputs do %>
<%= f.input :name %>
<%= link_to_remove_association "remove facility", f %>
<% end %>
</div>
Wesley, yes - you should be able to save both parent & nested at the same time. Long version: Yes, you can create a new record, before saving it, dynamically add some nested content & for the first time for either, save them both at the same time.
I believe your issue is probably in the _facility_fields.html.erb ... you have a <% f.inputs do %> that looks out of place or is just setup wrong. As you already have a do loop wrapping your render command, you shouldn't need this other do loop. That also means you want to remove the end thing from the template just above the /div.
_facility_fields.html.erb
<div class='nested-fields'>
<%= f.inputs do %> // Issue is this line
<%= f.input :name %>
<%= link_to_remove_association "remove facility", f %>
<% end %> // Remove this too afterwards
</div>
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
I'm trying to make a site that has a form with one model ("Requests") nested in another ("Orders"). Specifically, I'd like the orders/new page to have a form composed of requests that a user can fill and then submit, so they're all associated with the order that is created.
On someone here's suggestion, I looked into the Railscast on the topic (#196), and I've run into a problem I can't figure out, so I figured I'd ask. The problem is, I'm following his directions, but the request forms just aren't showing up. The form fields associated with the Order model ARE showing up, however, and I'm really confused, cause I basically copied the Railscast verbatim. Thoughts?
Here's my form code. It's specifically the part in the fields_for tag that isn't showing up on my site:
<%= form_for(#order) do |f| %>
<% if #order.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#order.errors.count, "error") %> prohibited this order from being saved:</h2>
<ul>
<% #order.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :user_name %><br />
<%= f.text_field :user_name %>
</p>
<p>
<%= f.label :user_email %><br />
<%= f.text_field :user_email %>
</p>
<% f.fields_for :requests do |builder| %>
<p>
<%= builder.label :item, "Item" %><br />
<%= builder.text_field :item %>
</p>
<p>
<%= builder.label :lbs, "LBs" %> <br />
<%= builder.text_field :lbs %>
</p>
<% end %>
<p><%= f.submit "Submit Order" %></p>
<% end %>
And here's my code for the two models, Order first:
class Order < ActiveRecord::Base
attr_accessible :order_status, :price_estimate, :price_final, :user_email, :user_name, :user_phone
has_many :requests, :dependent => :destroy
accepts_nested_attributes_for :requests
end
class Request < ActiveRecord::Base
attr_accessible :item, :lbs, :notes, :order_id, :status
belongs_to :order
end
Finally, in case it's relevant, the bit I added, per the cast's suggestions, to my Order controller create action:
def new
#order = Order.new
3.times { #order.requests.build }
respond_to do |format| # this part I copied from a tutorial. But when I commented it out, it didn't change anything, so I don't think this is the problem
format.html # new.html.erb
format.json { render json: #order }
end
end
Help? I'm super confused by this. I'm guessing the problem might have something to do with the "builder," but I'm new to this, and an hour or so of fiddling around hasn't yielded much.
Really appreciate any help. (Also, as a post-script. I'm giving up and going to bed, to look at this tomorrow. Sorry if I don't follow up on any questions til then).
Thanks!
I see two mistakes here.
In the view, replace:
<% f.fields_for :requests do |builder| %>
With:
<%= f.fields_for :requests do |builder| %>
In your order modeil, replace:
attr_accessible :order_status, :price_estimate, :price_final, :user_email, :user_name, :user_phone
with:
attr_accessible :order_status, :price_estimate, :price_final, :user_email, :user_name, :user_phone, :requests_attributes
The fields_for block doesn't output in a has_many relationship. This problem came up in a somewhat involved project I was working on. I broke it down to a very simple test case, but it still doesn't work. This question has been asked before and the problem was usually
that the nested object didn't exist. But here, the nested object does appear to exist, as explained in the code comments. I'm pretty new to rails so it could be something obvious.
Here is the simple case model code:
class Parent < ActiveRecord::Base
has_many :children
accepts_nested_attributes_for :children
end
class Child < ActiveRecord::Base
belongs_to :parent
end
Simple case controller:
class ParentController < ApplicationController
def index
#parent = Parent.find_by_id(1)
end
end
Simple case view:
<%= form_for #parent, {:url=>{:action=>:index}} do |f| %>
<!-- this outputs ok -->
<%= f.text_field :name %>
<% f.object.children.each do |c| %>
<!-- this outputs "child1", so the nested object exists -->
<%= c.name %>
<% f.fields_for c do |field| %>
this line does NOT output, nor does the field below
<%= field.text_field :name %>
<% end %>
<% end %>
<% end %>
I also tried this and saw the same result:
<%= form_for #parent, {:url=>{:action=>:index}} do |f| %>
<%= f.text_field :name %>
output here
<% f.fields_for :children do |field| %>
no output here nor the field below
<%= field.text_field :name %>
<% end %>
<% end %>
I also tried with a new #parent object in the controller and a #parent.build_child
(having changed the assoc to a has_one). That still saw the same result.
You've forgotten to put the = sign after <%.
Replace:
<% f.fields_for :children do |field| %>
with:
<%= f.fields_for :children do |field| %>