Nested forms in rails 4 and the fields_for method - ruby-on-rails

I am also having problems with nested forms and Rails 4 (this seems to be quite common unfortunately). I have events which have requirements, the models are:
class Event < ActiveRecord::Base
enum type: [:lecture, :exercise, :tutorial]
has_one :requirement, dependent: :destroy
#accepts_nested_attributes_for :requirement
end
and
class Requirement < ActiveRecord::Base
belongs_to :event
end
There is essentially a one-to-one correspondence between those two.
Now I would like to create a new event together with the associated
requirement. I am using the following form:
<div class="container">
<%= form_for(#event) do |f| %>
<% if #event.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#event.errors.count, "error") %> prohibited this event from being saved:</h2>
<ul>
<% #event.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="container">
<%= f.select :type, Event.types.map { |key, value| [key.humanize, key] }%>
<%= f.text_field :number, placeholder: "1298035" %>
<% f.fields_for :requirement, #event.requirement do |fields| %>
<%= fields.check_box :beamer %><br />
<% end %>
<%= f.submit %>
</div>
<% end %>
</div>
As you can see I would like to have a checkbox indicating whether a beamer is required. The problem is that the fields_for block is never evaluated. Similar to these posts:
Rails 3: fields_for showing blank filed on Edit view
Helper "fields_for" not working
As far as I can tell the objects are created properly:
# GET /events/new
def new
#event = Event.new
#event.build_requirement
end
If I use puts I see that both objects are not nil and that the associations are correct.
I am kind of new to rails and I must say that I'm stymied. Any ideas?

You should uncomment accepts_nested_attributes_for :requirement in the Event model.
Update:
You should also include = in the fields_for.
<%= f.fields_for :requirement, #event.requirement do |fields| %>

Related

Rails undefined method * for nil:NilClass

I am having an issue and I have done some reasearch, from my research I have found that the variable that is being used is empty, however I am unsure as to why it is empty, Maybe its something obvious to someone else?
I am trying to display a nested form on a page from another controller, I am used nested resources, Which I think might be my issue, but unsure how to resolve it.
Getting the following error:
undefined method `submission' for nil:NilClass
Structure of Project
Main Folders
-Members
--Questions
--Submissions
Concept:
Question - has_many - Submissions
Submission - Belongs_to - Question
Submission Model:
class Submission < ActiveRecord::Base
belongs_to :question
belongs_to :member
end
Question Model:
class Members::Question < ActiveRecord::Base
has_many :submissions
end
Submissions Controller:
def create
#question = Members::Question.find(params[:question_id])
#submission.member_id = current_member.id
#submission = #question.submissions.create(params[:submission].permit(:content, :question_id))
*Redirect Method Here *
end
In the form I am using the following method:
<%= form_for([#question, #question.submission.build]) do |f| %>
<% if #submission.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#submission.errors.count, "error") %> prohibited this submission from being saved:</h2>
<ul>
<% #submission.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :content %><br>
<%= f.text_area :content %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And then to display the form on the show page of the question, I am using
<%= render 'members/submissions/form' %>
Routes:
namespace :members do
resources :questions, only: [:index,:show] do
resources :submissions
end
end
Any one any ideas where I am going wrong?
Any help is appreciated.
I have solved the problem, Thank you for the suggestions, I was using the wrong variable, I was using #question, When because its nested, the correct variable is #members_question
Submissions Controller
def create
#members_question = Members::Question.find(params[:question_id])
#submission = #members_question.submissions.create(params[:submission].permit(:content, :question_id))
#submission.member_id = current_member.id
end
_form.html.erb
<%= form_for([#members_question, #members_question.submissions.build]) do |f| %>
<div class="field">
<%= f.label :content %><br>
<%= f.text_area :content %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>

Rails 4 - validate model is not working

Appreciate if you help me. I have a rails project, where people can book tickets to an airplanes (not a real project, just trying to learn rails :) ).
I have two cfaffolded objects - 'seats' and 'flights', and customer can buy a seat from every flight page (seats loads as partials).
My /app/views/flights/show.html.erb looks like that:
<p>
<strong>Departure:</strong>
<%= #flight.departure %>
</p>
<p>
<strong>Destination:</strong>
<%= #flight.destination %>
</p>
<p>
<strong>Baggage allowance:</strong>
<%= #flight.baggage_allowance %>
</p>
<%= render partial: "new_seat", locals: {seat: Seat.new(flight_id: #flight.id)} %>
<%= link_to 'Edit', edit_flight_path(#flight) %> |
<%= link_to 'Back', flights_path %>
My new_seat partial /app/views/flights/_new_seat.html.erb :
<h1>New Seat</h1>
<%= form_for(seat) do |f| %>
<% if seat.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(seat.errors.count, "error") %> prohibited this seat from being saved:</h2>
<ul>
<% seat.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.hidden_field :flight_id %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :baggage %><br>
<%= f.text_field :baggage %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
If it is important - I made new_seat partial by myself through copying it from /app/views/seats/new.html.erb
And now I need to validate baggage amount to prevent my clients grab big bags. I wrote my /app/models/seat.rb this way:
class Seat < ActiveRecord::Base
belongs_to :flight
def validate
if baggage > flight.baggage_allowance
seat.errors.add(:base, message: "You have too much baggage")
end
end
end
But it is not working - there is no errors on site when clients enters big amounts in baggage field. What am I doing wrong?
validate method is already available(its a class method that ActiveRecord provides us to implement our custom validations). You can use that method which AR provides. something like the code below
validate :check_baggage_limit
def check_baggage_limit
if baggage > self.flight.baggage_allowance
self.errors.add(:base, "You have too much baggage")
end
end
You can add your custom validations in two ways.
First is Custom method like below
class Seat < ActiveRecord::Base
belongs_to :flight
validate :baggage_limit
def baggage_limit
if baggage > flight.baggage_allowance
errors.add(:base, message: "You have too much baggage")
end
end
end
Second is Custom Validators
class BaggageValidator < ActiveModel::Validator
def validate(seat)
if seat.baggage > seat.flight.baggage_allowance
seat.errors.add(:base, message: "You have too much baggage")
end
end
end
class Seat < ActiveRecord::Base
include ActiveModel::Validations
belongs_to :flight
validates_with BaggageValidator
end
You must have misread the http://guides.rubyonrails.org/active_record_validations.html#custom-validators

How to get a nested text_area to render properly

I have a scaffold called submits that has a form for creating new submissions. I also created a model called question. I've used this model to create different questions in the submission form.I've utilized a join form and use active admin to add/edit questions from the backend. I'm getting this error.
undefined method `submit[question_ids][]' for #<Submit id: nil, name: nil, created_at: nil, updated_at: nil>
submits.rb
class Submit < ActiveRecord::Base
has_and_belongs_to_many :questions
end
question.rb
class Question < ActiveRecord::Base
has_and_belongs_to_many :submits
end
subits/_form.html.erb
<%= form_for(#submit) do |f| %>
<% if #submit.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#submit.errors.count, "error") %> prohibited this submit from being saved:</h2>
<ul>
<% #submit.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<div class="field">
<%= f.label :name,"Team Name" %><br>
<%= f.text_field :name, class: "form-control" %>
</div>
<% #questions.each do |question| %>
<div class="field">
<%= f.label(question.question)%>
<%= f.text_area "submit[question_ids][]" %>
</div>
<% end %>
<div class="actions">
<%= f.submit "Apply", class: "btn btn-primary btn-lg" %>
</div>
<% end %>
I'm guessing my error is here:
<%= f.text_area "submit[question_ids][]" %>
I'm just not sure what the correct syntax is. Any suggestions?
For Rails form_for input forms, you need :(whatever attribute) which should be defined in your migration file.
ex.) if you have 'text' attribute in your Submit model you can have your input form for the text attribute just like this. <%= f.text_area :text %>
But in this case it seems like you have a join table for your models, so I think you should fields_for for your join table.
cf.) How do i include Rails join table field in the form?

Rails: create two nested items in controller but only one shows in the view

Consider the following:
customer.rb
module Refinery
class Customer < Refinery::Core::BaseModel
has_many :users, :class_name => "Refinery::User"
accepts_nested_attributes_for :users
end
end
end
user_decorator.rb
Refinery::User.class_eval do
belongs_to :customer, :class_name => 'Refinery::Customer'
end
customer_controller.rb
module Refinery
class UsersController
def new
#customer = ::Refinery::Customer.new
# tried using build here as well with no sucess
#owner = #customer.users.new
#inputer = #customer.users.new
# raise #customer.users.length.to_yaml => returns 2 so that works!
end
end
end
new.html.erb
<%= form_for #customer do |f| %>
<% if #customer.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#customer.errors.count, "error") %> need to be corrected before continuing:</h2>
<ul>
<% #customer.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<!-- company fields here -->
<%= fields_for :users do |user| %>
<div>
<%= user.label :first_name %>
<%= user.text_field :first_name %>
</div>
<div>
<%= user.label :last_name %>
<%= user.text_field :last_name %>
</div>
<!-- more user fields here etc -->
<% end $>
<% end %>
When I view this page only one user shows up. The ids for the fields look like this also:
<div>
<label for="users_last_name">Last name</label>
<input id="users_last_name" name="users[last_name]" size="30" type="text">
</div>
I think there should be some kind of index in there right? (i.e. 0, 1, 2 etc for as if iterating over an array.
What am I doing wrong?
You missed the
f.fields_for
Just add it and it should work

Can't get multi-model form to work

I have an Appointment model where each Appointment has a client_id. When an Appointment is created, I want the user to be able to type the client's name into an autocomplete field so a new Client is created if the name the user typed in doesn't already have a Client record. (I've done this exact same thing in other frameworks.)
Here's what my Appointment model looks like:
class Appointment < ActiveRecord::Base
has_many :appointment_services
belongs_to :client
accepts_nested_attributes_for :client
end
And here's what my form looks like:
<%= form_for(#appointment) do |f| %>
<% if #appointment.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#appointment.errors.count, "error") %> prohibited this appointment from being saved:</h2>
<ul>
<% #appointment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.fields_for :client do |client_form| %>
<div class="field">
<%= client_form.label :name %>
<%= client_form.text_field :name %>
</div>
<% end %>
For some reason nothing inside <%= f.fields_for :client do... shows up on the screen. What am I doing wrong?
Try
<%= f.fields_for #client do |client_form| %>
and don't forget to initialize #client in your controller

Resources