Simple_form multiple select field doesn't work - ruby-on-rails

new rails user here. I'm trying to have my schedule form store an array of "days" but after several attempts I just can't make it work.
Here are my codes currently
*schedules/_form.html.erb:*
<%= simple_form_for #schedule do |f| %>
<% if #schedule.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#schedule.errors.count, "error") %> prohibited this schedule from being saved:</h2>
<ul>
<% #schedule.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.input :section_id do %>
<%= f.select :section_id, Section.all.map{|s| [s.seccon, s.id]}, :include_blank => true %>
<% end %>
<%= f.association :subject %>
<%= f.collection_select :day_ids, #days, :id, :name, {}, {:multiple => true, :size => 1} %>
<div class="field">
<%= f.label :start_time %>
<%= f.time_select :start_time %>
</div>
<%= f.input :professor do %>
<%= f.select :professor_id, Professor.all.map{|j| [j.procon, j.id]}, :include_blank => true %>
<% end %>
<%= f.association :room %>
<%= f.button :submit %>
<% end %>
*schedules_controller.rb:*
class SchedulesController < ApplicationController
before_action :set_schedule, only: [:show, :edit, :update, :destroy]
# GET /schedules
# GET /schedules.json
def index
#schedules = Schedule.all
#days = Day.all
end
# GET /schedules/1
# GET /schedules/1.json
def show
end
# GET /schedules/new
def new
#schedule = Schedule.new
#days = Day.all
end
# GET /schedules/1/edit
def edit
end
# POST /schedules
# POST /schedules.json
def create
#schedule = Schedule.new(schedule_params)
#days = Day.all
respond_to do |format|
if #schedule.save
format.html { redirect_to #schedule, notice: 'Schedule was successfully created.' }
format.json { render action: 'show', status: :created, location: #schedule }
else
format.html { render action: 'new' }
format.json { render json: #schedule.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /schedules/1
# PATCH/PUT /schedules/1.json
def update
respond_to do |format|
if #schedule.update(schedule_params)
format.html { redirect_to #schedule, notice: 'Schedule was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #schedule.errors, status: :unprocessable_entity }
end
end
end
# DELETE /schedules/1
# DELETE /schedules/1.json
def destroy
#schedule.destroy
respond_to do |format|
format.html { redirect_to schedules_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_schedule
#schedule = Schedule.find(params[:id])
#days = Day.all
end
# Never trust parameters from the scary internet, only allow the white list through.
def schedule_params
params.require(:schedule).permit(:section_id, :subject_id, :start_time, :finish_time_id, :professor_id, :room_id, :day_ids)
end
end
schedule.rb:
class Schedule < ActiveRecord::Base
belongs_to :section
belongs_to :subject
belongs_to :finish_time
has_and_belongs_to_many :days
accepts_nested_attributes_for :days, :allow_destroy => true
validates :section_id, :subject_id, :start_time, :professor_id, :room_id, :presence => true
belongs_to :professor
belongs_to :room
end
day.rb:
class Day < ActiveRecord::Base
has_and_belongs_to_many :schedules
default_scope { order(:id)}
has_paper_trail
validates :name, :desc, :presence => true
end

As was said here, the best thing to do is to create a has_many model relationship between Schedule and Day. You'll need a separate join table to make the relationship work. It will have: schedule_id and day_id as the two columns. You'd do this because you have a many > many relationship. There can be many schedules that belong to a day and many days that belong to a schedule.
I used this scenario in my app:
Recipe.rb
class Recipe < ActiveRecord::Base
has_and_belongs_to_many :wines
default_scope { order(:name) }
end
Wine.rb
class Wine < ActiveRecord::Base
has_and_belongs_to_many :recipes
accepts_nested_attributes_for :recipes, :allow_destroy => true
end
Migration
class AddRecipesWinesJoinTable < ActiveRecord::Migration
def self.up
create_table :recipes_wines, :id => false do |t|
t.column :recipe_id, :integer, :null => false
t.column :wine_id, :integer, :null => false
end
add_index :recipes_wines, [:wine_id]
end
def self.down
remove_index :recipes_wines, [:wine_id]
drop_table :recipes_wines
end
end
_wine_form.html.erb
# #recipes is Recipe.all generated by the controller
<%= w.collection_select :recipe_ids, #recipes, :id, :name, {}, {:multiple => true, :size => 6, :style => 'width:100%'} %>
Hope this helps.

Related

Rails .build is not building has_many :options

I have a Poll app with 3 models.
Poll.rb
class poll < ApplicationRecord
validates_presence_of :user, :title
belongs_to :user
has_many :questions, dependent: :destroy
has_many :options, through: :questions
accepts_nested_attributes_for :questions
end
Question.rb
class Question < ApplicationRecord
validates_presence_of :poll_id, :question_id, :title
belongs_to :poll
has_many :options
accepts_nested_attributes_for :options, reject_if: proc { |attributes| attributes['title'].blank? }
end
Option.rb
class Option < ApplicationRecord
validates_presence_of :question_id, :title
belongs_to :question
belongs_to :poll
end
I want the question form to have a field for adding options so I've added this to the question _form.
<%= form.fields_for :option do |o| %>
<div>
<%= o.label "Option", style: "display: block" %>
<%= o.text_field :title, placeholder: "Enter Option here" %>
</div>
<% end %>
I can now see an option block which is good. Although I wish to have 3 possbile options so in the questions_controller.rb I've added the following:
def new
#question = #poll.questions.build
3.times { #question.options.build } # 3 different options
end
Despite this I'm only seeing one option block instead of the 3. Why is this the case and how do i fix? Additionally I'm not seeing new entries into the options postgresql table.
Full questions_controller.rb
class QuestionsController < ApplicationController
before_action :set_question, only: %i[ show edit update destroy ]
before_action :set_poll
# GET /questions or /questions.json
def index
#questions = Question.all
end
# GET /questions/1 or /questions/1.json
def show
end
# GET /questions/new
def new
# #question = Question.new
#question = #poll.questions.build
3.times { #question.options.build } # 5 different options
end
# GET /questions/1/edit
def edit
end
# POST /questions or /questions.json
def create
#question = Question.new(question_params)
respond_to do |format|
if #question.save
format.html { redirect_to polls_question_url(#question), notice: "Question was successfully created." }
format.json { render :show, status: :created, location: #question }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /questions/1 or /questions/1.json
def update
respond_to do |format|
if #question.update(question_params)
format.html { redirect_to polls_question_url(#question), notice: "Question was successfully updated." }
format.json { render :show, status: :ok, location: #question }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
# DELETE /questions/1 or /questions/1.json
def destroy
poll_id = Question.find_by(params[:poll_id])
session[:return_to] ||= request.referer
#question.destroy
respond_to do |format|
format.html { redirect_to session.delete(:return_to), notice: "Question was successfully destroyed." }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_question
#question = Question.find(params[:id])
end
# Only allow a list of trusted parameters through.
def question_params
params.require(:question).permit(:poll_id, :question_type, :title, :description, :randomize_selection, :voter_abstain, { option_attributes: [:question_id, :poll_id, :party_id, :title, :description] } )
end
def set_poll
#poll = poll.find_by(params[:poll_id])
end
end
routes.rb
resources :users do
resources :polls
end
resource :polls do
resources :questions
end
resource :questions do
resources :options
end
Edit:
Here is my questions form partial.
_form.html.erb
<%= form_with(model: [#Poll, question] ) do |form| %>
<% if question.errors.any? %>
<div style="color: red">
<h2><%= pluralize(question.errors.count, "error") %> prohibited this question from being saved:</h2>
<ul>
<% question.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<div>
<%= form.hidden_field :poll_id %>
</div>
<div>
<%= form.label :question_type, style: "display: block" %>
<%= form.text_field :question_type %>
</div>
<div>
<%= form.label :title, style: "display: block" %>
<%= form.text_field :title %>
</div>
<div>
<%= form.label :description, style: "display: block" %>
<%= form.text_area :description %>
</div>
<div>
<%= form.label :randomize_selection, style: "display: block" %>
<%= form.check_box :randomize_selection %>
</div>
<div>
<%= form.label :voter_abstain, style: "display: block" %>
<%= form.check_box :voter_abstain %>
</div>
<div>
<%= form.fields_for :options do |o| %>
<div>
<%= o.label "Option", style: "display: block" %>
<%= o.text_field :title, placeholder: "Enter Option here" %>
</div>
<% end %>
</div>
<div>
<%= form.submit %>
</div>
<% end %>
Here is the poll's show where I am rendering the forms.
show.html.erb
<p style="color: green"><%= notice %></p>
<p>
<strong>Poll Title:</strong>
<%= #poll.title %>
<%= render #poll %>
</p>
<div>
<%= link_to "Edit this poll", edit_user_poll_path(#poll) %> |
<%= link_to "Back to polls", user_polls_path %> |
<%= link_to "Destroy this poll", user_poll_path(#poll), method: :delete %>
</div>
<% if #poll.questions.any? %>
<hr>
<h2>Questions:</h2>
<%= render #poll.questions %>
<% end %>
<hr>
<h2>Add a new Question:</h2>
<%= render "questions/form", question: #poll.questions.build %>
The argument you pass to fields_for has to match the name of the assocation on the model:
<%= form.fields_for :options do |o| %>
<div>
<%= o.label "Option", style: "display: block" %>
<%= o.text_field :title, placeholder: "Enter Option here" %>
</div>
<% end %>
Pay very careful attention to plurization in Rails. Its a huge part of getting Convention over Configuration to work for you instead of against you.
However there are a quite a few other problems with this code.
Constants should always be CamelCase or UPPERCASE in Ruby - you need to change class poll to class Poll and fix all the references to the class. This isn't just a matter of style since the interpreter treats identifiers that start with an uppercase letter completely differently.
You're not nesting it properly. You have a nested route but you're still treating it like a non-nested resource in your controller and docstrings.
You're passing the parent id in your params whitelist. :poll_id and :question_id should not be whitelisted. Do not pass the parent id with a hidden input. The question id is assigned by Rails - you should not trust the user to pass it.
The option should not need a poll_id. Use an indirect has_one assocation to go up the tree. This could cause a edge case where a question and its options belong to different polls.
First lets fix the models:
class Poll < ApplicationRecord
# belongs_to assocations are required by default
# adding validations will just cause duplicate error messages
validates_presence_of :title
belongs_to :user
has_many :questions, dependent: :destroy
has_many :options, through: :questions
accepts_nested_attributes_for :questions
end
class Question < ApplicationRecord
validates_presence_of :title
belongs_to :poll
has_many :options
accepts_nested_attributes_for :options, reject_if: proc { |attributes| attributes['title'].blank? }
end
class Option < ApplicationRecord
validates_presence_of :title
belongs_to :question
has_one :poll, through: :question
end
Then I would recommend that you use shallow nesting
resource :polls do
resources :questions, shallow: true
end
This creates the questions member routes (show, edit, delete) without the /polls/:poll_id prefix while the collection routes (index, create, new) are nested.
And that you set controller up as:
class QuestionsController < ApplicationController
before_action :set_question, only: %i[ show edit update destroy ]
before_action :set_poll, only: %i[ new create index ]
# GET /polls/1/questions or /polls/1/questions.json
def index
#questions = #poll.questions.all
end
# GET /questions/1 or /polls/1/questions/1.json
def show
end
# GET /polls/1/questions/new
def new
# build is just an alias of new for legacy compatibility with Rails 2...
# its about time that we ditch it
#question = #poll.questions.new
3.times { #question.options.new } # 5 different options
end
# GET /questions/1/edit
def edit
end
# POST /polls/1/questions or /polls/1/questions.json
def create
#question = #poll.questions.new(question_params)
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: "Question was successfully created." }
format.json { render :show, status: :created, location: #question }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /questions/1 or /questions/1.json
def update
respond_to do |format|
if #question.update(question_params)
format.html { redirect_to #question, notice: "Question was successfully updated." }
format.json { render :show, status: :ok, location: #question }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
# DELETE /questions/1 or /questions/2.json
def destroy
session[:return_to] ||= request.referer
#question.destroy
respond_to do |format|
format.html { redirect_to session.delete(:return_to), notice: "Question was successfully destroyed." }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_question
#question = Questions.find(params[:id])
end
# Only allow a list of trusted parameters through.
def question_params
# do not write this in a single unreadable line
params.require(:question).permit(
:question_type,
:title,
:description,
:randomize_selection,
:voter_abstain,
# do not wrap hash arguments in brackets
# as it will break if/when the `permit` method is changed to use real keyword arguments
# for has_many assocations the key naming convention is also plural_attributes
options_attributes: [
:party_id,
:title,
:description
]
)
end
def set_poll
#poll = Poll.find_by(params[:poll_id])
end
end
The key difference here is that you should look up the poll by the parameter in the URL for the nested routes and create the question off the poll instance (which sets poll_id).
Added:
You're not actually using the model you initialized in your controller. If you want to render the form from a completely different action you need to initialize the instance variable there:
class PollsController < ApplicationController
def show
#question = #poll.questions.new
3.times { #question.options.new } # 5 different options ???
end
# ...
end
<%= render "questions/form", question: #question %>
And in your partial you have a sneaky little bug. Ruby is case sensitive so #poll and #Poll are actually different variables.
irb(main):049:0> #foo = "bar" => "bar"
irb(main):050:0> #Foo
=> nil
Since instance variables are auto-vivified you're just get an unexpected nil instead of an error. What you actually want is:
<%= form_with(model: [#poll, question] ) do |form| %>

Updating nested fields_for and collection_select in Rails

Really stumped here. I'm trying to get my form to update the categories on the edit form. Problem is, everything in my form updates when submitted except the categories. It ends up inserting the new category chosen like it's going through the create method instead of the update method, so when the edit form is shown again after submission, it keeps doubling the fields of categories. 1, then 2, then 4, then 8, etc. after each submission. Please please help anyone. Appreciate it.
views/blog_posts/edit.html.erb
<div class="col-md-6 col-md-offset-3 blog-submit">
<%= form_for #blog_post do |b| %>
<%= b.label :title %>
<%= b.text_field :title %><br>
<%= b.fields_for :categorizations do |cat| %>
<%= cat.label :category_name, "Category 1" %>
<%= cat.collection_select(:category_id, Category.all, :id, :category_name, {blank: "Select Category"}) %>
<%= link_to "Add Categories", new_category_path %>
<br>
<% end %>
<%= b.submit "Submit", class: "btn btn-primary" %>
<% end %>
</div>
Blog_post controller:
class BlogPostsController < ApplicationController
protect_from_forgery
before_action :authenticate_admin!, only: [:new, :edit]
def index
#blog_posts = BlogPost.order(id: :desc)
end
def new
#blog_post = BlogPost.new
#blog_post.categorizations.build.build_category
#blog_post.categories.build
end
def edit
#blog_post = BlogPost.find(params[:id])
end
def create
#blog_post = BlogPost.new(blog_post_params)
respond_to do |format|
if #blog_post.save
format.html { redirect_to #blog_post, notice: 'Your blog was submitted successfully' }
format.json { render :show, status: :created, location: #blog_post }
else
format.html { render :new }
format.json { render json: #blog_post.errors, status: :unprocessable_entity }
end
end
puts #blog_post.errors.inspect
end
def update
#blog_post = BlogPost.find(params[:id])
if #blog_post.update_attributes(blog_post_params)
render 'show'
else
render 'edit'
end
end
def show
#blog_post = BlogPost.find(params[:id])
end
private
def blog_post_params
params.require(:blog_post).permit(:title, :content, :posted_by, :comments, :blog_pic, {categorizations_attributes: [:category_id, :category_name]})
end
end
models:
class BlogPost < ApplicationRecord
has_many :categorizations
has_many :categories, :through => :categorizations
accepts_nested_attributes_for :categorizations
has_many :comments
mount_uploader :blog_pic, BlogPicUploader
end
class Categorization < ApplicationRecord
belongs_to :blog_post
belongs_to :category
end
class Category < ApplicationRecord
has_many :categorizations
has_many :blog_posts, :through => :categorizations
end
Add id in blog_post_params as shown below. This will work for you.
def blog_post_params
params.require(:blog_post).permit(:title, :content, :posted_by, :comments, :blog_pic, {categorizations_attributes: [:id,:category_id, :category_name]})
end

Nested form working in new but not showing up in edit Rails

I'm making a invoice application where i have the #invoice form and inside it i have nested forms for customers, products, and company information. The products form is working fine in all views but the customer form isn't. When i fill in the customer information and create a new invoice it works. But when i try to edit that invoice the entire form is gone.
invoice/_form
<%= form_for #invoice do |f| %>
<% if #invoice.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#invoice.errors.count, "error") %> prohibited this invoice from being saved:</h2>
<ul>
<% #invoice.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.fields_for :customer do |customer| %>
<div class="field">
<%= customer.label 'Bedrijfsnaam ontvanger' %><br/>
<%= customer.text_field :company_name, placeholder: 'bedrijfsnaam', class: 'form-control' %>
</div>
<div class="field">
<%= customer.label 'Adres ontvanger' %><br>
<%= customer.text_field :address_line_1, placeholder: 'adres ontvanger', class: 'form-control' %>
</div>
<div class="field">
<%= customer.label 'Postcode & stad' %><br>
<%= customer.text_field :zip_code, placeholder: '1234AB Rotterdam', class: 'form-control' %>
</div>
<% end %>
Invoices_controller.rb
class InvoicesController < ApplicationController
before_action :set_invoice, only: [:show, :edit, :update, :destroy]
# GET /invoices
# GET /invoices.json
def index
#invoices = Invoice.all
end
# GET /invoices/1
# GET /invoices/1.json
def show
end
# GET /invoices/new
def new
#invoice = Invoice.new
#invoice.products.build
#invoice.build_customer
end
# GET /invoices/1/edit
def edit
end
# POST /invoices
# POST /invoices.json
def create
#invoice = Invoice.new(invoice_params)
respond_to do |format|
if #invoice.save
format.html { redirect_to #invoice, notice: 'Invoice was successfully created.' }
format.json { render :show, status: :created, location: #invoice }
else
format.html { render :new }
format.json { render json: #invoice.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /invoices/1
# PATCH/PUT /invoices/1.json
def update
respond_to do |format|
if #invoice.update(invoice_params)
format.html { redirect_to #invoice, notice: 'Invoice was successfully updated.' }
format.json { render :show, status: :ok, location: #invoice }
else
format.html { render :edit }
format.json { render json: #invoice.errors, status: :unprocessable_entity }
end
end
end
# DELETE /invoices/1
# DELETE /invoices/1.json
def destroy
#invoice.destroy
respond_to do |format|
format.html { redirect_to invoices_url, notice: 'Invoice was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_invoice
#invoice = Invoice.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def invoice_params
params.require(:invoice).permit(:number, :currency, :date, :duedate, :btwtotal,
:subtotal, :total, :footer, customers_attributes: [:id, :company_name, :address_line_1, :zip_code, :_destroy],
companies_attributes: [:id, :btw_number, :iban_number, :kvk_number, :company_name, :_destroy],
products_attributes: [:id, :quantity, :description, :unitprice, :btw, :total])
end
end
Invoice.rb - (model)
class Invoice < ActiveRecord::Base
has_one :company
has_one :customer
has_many :products
accepts_nested_attributes_for :customer, reject_if: :all_blank, allow_destroy: true
accepts_nested_attributes_for :products, reject_if: :all_blank, allow_destroy: true
validates :number, :currency, :date, :duedate, :btwtotal, :subtotal, :total, presence: true
end
In the invoices controller try changing customers_attributes to customer_attributes in your strong params:
customer_attributes: [:id, :company_name, :address_line_1, :zip_code, :_destroy]
I suspect this is an issue where your customer nested attributes are not being properly saved, so when you go to the edit view that part of the form isn't being rendered because there isn't any customer saved for your invoice

undefined method `facilities' for nil:NilClass - Nested actions

I have an "undefined method" issue with my app, and don't find where it comes from :(.
In my app, i have 4 models :
Deal, Pool (which belongs to deal), Facility (which belongs to pool), Facilityschedule (which belongs to Facility).
class Deal < ActiveRecord::Base
has_many :pools, :dependent => :destroy
accepts_nested_attributes_for :pools, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
end
class Pool < ActiveRecord::Base
belongs_to :deal
has_many :facilities, :dependent => :destroy
accepts_nested_attributes_for :facilities, :allow_destroy => true
end
class Facility < ActiveRecord::Base
belongs_to :pool
has_many :facilityschedules, :dependent => :destroy
accepts_nested_attributes_for :facilityschedules, :reject_if => lambda { |a| a[:date].blank? }, :allow_destroy => true
end
class Facilityschedule < ActiveRecord::Base
belongs_to :facility
end
I have a partial form which allows the user to create all of these :
<%= form_for(#deal) do |f| %>
<% if #deal.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#deal.errors.count, "error") %> prohibited this deal from being saved:</h2>
<ul>
<% #deal.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name, "Deal name"%>
<%= f.text_field :name %>
<br/>
</div>
<div>
<%= f.fields_for :pools do |builder|%>
<%= builder.label :name, "Pool name" %>
<%= builder.text_field :name, :rows => 3 %>
<%= builder.check_box :_destroy %>
<%= builder.label :_destroy, "Remove Pool" %>
<br/>
<%= builder.fields_for :facilities do |fbuilder|%>
<%= fbuilder.label :name, "Facility name" %>
<%= fbuilder.text_field :name, :rows => 3 %>
<%= fbuilder.check_box :_destroy %>
<%= fbuilder.label :_destroy, "Remove Facility" %>
<br/>
<%= fbuilder.fields_for :facilitieschedules do |sbuilder|%>
<%= sbuilder.label :date, "Schedule" %>
<%= sbuilder.text_field :date, :rows => 3 %>
<%= sbuilder.check_box :_destroy %>
<%= sbuilder.label :_destroy, "Remove Schedule" %>
<br/>
</div>
<% end %>
<% end %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And finally, i have my Deal controller where the issue is located (new action) :
class DealsController < ApplicationController
before_action :set_deal, only: [:show, :edit, :update, :destroy]
# GET /deals
# GET /deals.json
def index
#deals = Deal.all
end
# GET /deals/1
# GET /deals/1.json
def show
end
# GET /deals/new
def new
#deal = Deal.new
2.times do
pool = #deal.pools.build
2.times do
**facility = #pool.facilities.build**
1. times { facility.facilityschedules.build }
end
end
end
# GET /deals/1/edit
def edit
end
# POST /deals
# POST /deals.json
def create
#deal = Deal.new(deal_params)
respond_to do |format|
if #deal.save
format.html { redirect_to #deal, notice: 'Deal was successfully created.' }
format.json { render :show, status: :created, location: #deal }
else
format.html { render :new }
format.json { render json: #deal.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /deals/1
# PATCH/PUT /deals/1.json
def update
respond_to do |format|
if #deal.update(deal_params)
format.html { redirect_to #deal, notice: 'Deal was successfully updated.' }
format.json { render :show, status: :ok, location: #deal }
else
format.html { render :edit }
format.json { render json: #deal.errors, status: :unprocessable_entity }
end
end
end
# DELETE /deals/1
# DELETE /deals/1.json
def destroy
#deal.destroy
respond_to do |format|
format.html { redirect_to deals_url, notice: 'Deal was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_deal
#deal = Deal.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def deal_params
params.require(:deal).permit(:name, pools_attributes: [:id, :name, :number, :deal_id, :_destroy, facilities_attributes: [:id, :name, :pool_id, :_destroy, facilityschedules_attributes: [:id, :facility_id, :date, :_destroy]]])
end
end
When i try to create a new deal, the following error message pops up "undefined method `facilities' for nil:NilClass" (in bold in the Deal controller, above).
What am i doing wrong?
Many thanks and have a good week end :)
# GET /deals/new
def new
#deal = Deal.new
2.times do
pool = #deal.pools.build
2.times do
**facility = #pool.facilities.build**
1. times { facility.facilityschedules.build }
end
end
end
In the code above you have never set the #pool variable, but instead set pool.
Undefined method for Nil::NilClass is never about not having declared the method, it's that you're trying to call it on a nil object, which is an object of NilClass.
There are also some strange patterns in this method. I've never seen the ** around code in Rails. Are you trying to comment out the line?
Would this work better?
# GET /deals/new
def new
#deal = Deal.new
2.times do
#pool = #deal.pools.build
2.times do
facility = #pool.facilities.build
facility.facilityschedules.build
end
end
end

Rails: Globalize3 and batch_translations

I'm using rails 3.2.8, globalize3 and batch_translations to translate specific content for an little cms and shop system.
I integrated it without problems for one translation on one model. So everthings works fine. I started adding this functionality for my other models and..shhhhh weird things happen.
Status now: I can create new content with translations. Everything ok. But if I try to edit/update the values in the translations tables nothing happen! Maybe there is a wrong parameter path in batch_translations or something...
Here an example for categories!
migration_file
class CreateCategories < ActiveRecord::Migration
def self.up
create_table :categories do |t|
t.timestamps
end
Category.create_translation_table! :category_name => :string, :description => :string
end
def self.down
Category.drop_translation_table!
drop_table :categories
end
end
model:
class Category < ActiveRecord::Base
attr_accessible :category_name, :description
attr_accessible :translations_attributes
translates :category_name, :description
has_many :translations
accepts_nested_attributes_for :translations
class Translation
attr_accessible :locale, :category_name, :description
end
end
this weird class Translation I wrote because I got mass-assignemnt errors for locale, etc...
form:
<div>
<%= form_for #category, html: { :multipart => true } do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= build_translation_text_field f, :category_name, :description %>
<%= f.submit (t ".save"), class: "btn btn-large btn-primary" %>
<% end %>
</div>
helper for my translation form:
def build_translation_text_field(f, *atts)
tag = content_tag(:h1, "Test")
I18n.available_locales.each do |l|
f.globalize_fields_for l do |g|
atts.each do |a|
tag += content_tag(:div, content_tag(:h4, t(a)+":"))
tag += (g.text_field a, class: l)
end
end
end
tag
end
categories_controller update method:
def create
#category = Category.new(params[:category])
if #category.save
#categories = Category.all
flash[:success] = t(:category_created)
respond_to do |format|
format.html {render 'index'}
format.js
end
else
flash[:error] = #category.errors.full_messages.each {|msg| p msg}
#categories = Category.all
respond_to do |format|
format.html {render 'new'}
format.js
end
end
end
def update
#category = Category.find(params[:id])
if #category.update_attributes(params[:category])
#categories = Category.all
flash[:success] = t(:category_updated)
respond_to do |format|
format.html {render 'index'}
format.js
end
else
flash[:error] = #category.errors.full_messages.each {|msg| p msg}
#categories = Category.all
respond_to do |format|
format.html {render 'edit'}
format.js
end
end
end
anyone an idea or have an working example with two models whit one or more translated attributes?
My fault:
Update for the model:
class Category < ActiveRecord::Base
attr_accessible :category_name, :description
attr_accessible :translations_attributes
translates :category_name, :description
# has_many :translations <-- delete this
accepts_nested_attributes_for :translations
class Translation
attr_accessible :locale, :category_name, :description
end
end

Resources