Rails nomethod error - ruby-on-rails

I'm new to Rails and am trying to create an application that takes a user request. However this is what is happening when I am trying to create a new request.
Request Controller:
class RequestsController < ApplicationController
before_action :set_request, only: [:show, :edit, :update, :destroy]
# GET /requests
# GET /requests.json
def index
#requests = Request.all
end
# GET /requests/1
# GET /requests/1.json
def show
end
# GET /requests/new
def new
#request = Request.new
end
# GET /requests/1/edit
def edit
end
# POST /requests
# POST /requests.json
def create
#request = Request.new(request_params)
respond_to do |format|
if #request.save # <-------------- The problem is here
format.html { redirect_to #request, notice: 'Request was successfully created.' }
format.json { render :show, status: :created, location: #request }
else
format.html { render :new }
format.json { render json: #request.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /requests/1
# PATCH/PUT /requests/1.json
def update
respond_to do |format|
if #request.update(request_params)
format.html { redirect_to #request, notice: 'Request was successfully updated.' }
format.json { render :show, status: :ok, location: #request }
else
format.html { render :edit }
format.json { render json: #request.errors, status: :unprocessable_entity }
end
end
end
# DELETE /requests/1
# DELETE /requests/1.json
def destroy
#request.destroy
respond_to do |format|
format.html { redirect_to requests_url, notice: 'Request was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_request
#request = Request.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def request_params
params.require(:request).permit(:user_id, :description, :created)
end
end
The error says there is no "Create" method in the requests controller, however the method that is saying this is the create method. I think that a problem is that my view isn't passing the description as a parameter and I'm not sure how to do that/why it's not already.
_form.html.erb (Rendered by edit.html.erb):
%= form_for(#request) do |f| %>
<% if #request.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#request.errors.count, "error") %> prohibited this request from being saved:</h2>
<ul>
<% #request.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<center>
<div class="field">
<%= f.label 'Describe your favor' %><br>
<%= f.text_area :description %>
</div>
<div class="actions">
<%= f.submit %>
</div>
</center>
<% end %>
If someone could show me how to pass the description object as a parameter to my create method and get the method to not crash.
Here is the error log:
NoMethodError (undefined method `Request' for #<Request:0x007f9fbd8992e8>):
app/controllers/requests_controller.rb:32:in `block in create'
app/controllers/requests_controller.rb:31:in `create'
Rendered /usr/local/rvm/gems/ruby-2.2.2/gems/actionpack-4.2.5/lib/action_dispatch/middleware/templates/rescues/_source.erb (6.9ms)
Rendered /usr/local/rvm/gems/ruby-2.2.2/gems/actionpack-4.2.5/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (2.8ms)
Rendered /usr/local/rvm/gems/ruby-2.2.2/gems/actionpack-4.2.5/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (0.9ms)
Rendered /usr/local/rvm/gems/ruby-2.2.2/gems/actionpack-4.2.5/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (29.4ms)

Using Request (or Response) as the name of a model is not a very good idea since you will end up shadowing the request object. Which is a core part of Rails controllers.
It will also make it very confusing to reason about your code since it will collide with a core concept in MVC and web development in general.
Use a thesaurus and find another name for your model.

Related

RJS Dynamic update ActionView::Template::Error (undefined method `each' for nil:NilClass)

I am using Rails 4.2.6/PostgreSQL and trying to make dynamic update in index that has form and generate by scaffold. I think I am doing right but having issue with render partial via rjs. Bellow is an error and code. Any idea? Or RJS still available in Rails 4??
Server
Started POST "/users" for 127.0.0.1 at 2016-06-21 18:50:59 -0700
Processing by UsersController#create as JS
Parameters: {"utf8"=>"✓", "user"=>{"name"=>"Tim"}, "commit"=>"Create User"}
(0.3ms) BEGIN
SQL (0.9ms) INSERT INTO "users" ("name", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["name", "Tim"], ["created_at", "2016-06-22 01:50:59.194072"], ["updated_at", "2016-06-22 01:50:59.194072"]]
(63.8ms) COMMIT
Rendered users/_user.html.erb (37.6ms)
Rendered users/create.js.erb (42.8ms)
Completed 500 Internal Server Error in 145ms (ActiveRecord: 65.4ms)
ActionView::Template::Error (undefined method `each' for nil:NilClass):
1: <% #users.each do |user| %>
2: <tr>
3: <td><%= user.name %></td>
4: <td><%= link_to 'Show', user %></td>
app/views/users/_user.html.erb:1:in `_app_views_users__user_html_erb___2381841639716957386_70119033868960'
app/views/users/create.js.erb:1:in `_app_views_users_create_js_erb__1865303298608397742_70119034321000'
app/controllers/users_controller.rb:30:in `create'
create.js.erb
$("#users").append("<%= escape_javascript(render #user) %>");
users_controller.rb
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
# GET /users.json
def index
#users = User.all
#user = User.new
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
#user = User.new
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
format.js
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:name)
end
end
app/views/users/index.html
<p id="notice"><%= notice %></p>
<h1>Listing Users</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody id="users">
<%= render #user %>
</tbody>
</table>
<br>
<%= render 'form' %>
app/views/users/_form.html.erb
<%= form_for(#user, remote: true) do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
If I put something like #users = User.all in create action, it will renders all users twice as you can see in below image.
After tries and errors, I have confirmed there is an answer in Rajesh's comments. It was bit unclear in the process of tries but here is how I figure this out.
create.js.erb
Before
$("#users").append("<%= escape_javascript(render #user) %>");
After
$("#users").html("<%= escape_javascript(render #user) %>");
users_controller.rb
Before
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
format.js
else
.
.
After
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
#users = User.all
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
format.js
else
.
.
Then everything works fine.
These are actually very make sense for both, each for nil error and appended rendering behavior. Thanks for answering comment Rajesh. Next time, please try post it in answer section.

Find record in table and save id to another table in Rails

I'm developing an app in which users can have a personal food diary.
It's pretty simple: a user can search for a nutrient on a Nutrients table (let's say milk) - currently through a pretty simple search form - and then should be able to save the amount he consumed of this nutrient (together with the nutrient_id) on a second table, which is called Diaries (that holds the nutrient_id as foreign key and an integer field called "amount").
My search works. I can also create new records in Diaries but I have to type in the nutrient_id manually.
My question is now how I can make this easily work? Ideally a user finds a nutrient clicks on it and will be redirected to a page that shows this nutrient together with a field for "amount" and a save button to save both information (nutrient_id and amount) on the Diaries table.
At the end of the day I think the user will be directed to the new action of my diary controller - the question is how my app sets the nutrient_id for this action for the nutrient the user selected before?
Sorry if this is a too simple question but I just started coding few weeks ago.
Thanks a lot for help!
My code looks like as follows:
nutrient.rb
class Nutrient < ActiveRecord::Base
has_many :diaries
def self.search(search)
where("name LIKE ?", "%#{search}%")
end
end
diary.rb
class Diary < ActiveRecord::Base
belongs_to :nutrient
end
nutrients_controller.rb
class NutrientsController < ApplicationController
before_action :set_nutrient, only: [:show, :edit, :update, :destroy]
# GET /nutrients
# GET /nutrients.json
def index
#nutrients = Nutrient.all
end
def search
if params[:search]
#nutrients = Nutrient.search(params[:search]).order("created_at DESC")
if #nutrients.present?
#nutrients
else
flash[:notice] = "Nutrient not found in database"
end
end
end
# GET /nutrients/1
# GET /nutrients/1.json
def show
end
# GET /nutrients/new
def new
#nutrient = Nutrient.new
end
# GET /nutrients/1/edit
def edit
end
# POST /nutrients
# POST /nutrients.json
def create
#nutrient = Nutrient.new(nutrient_params)
respond_to do |format|
if #nutrient.save
format.html { redirect_to #nutrient, notice: 'Nutrient was successfully created.' }
format.json { render :show, status: :created, location: #nutrient }
else
format.html { render :new }
format.json { render json: #nutrient.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /nutrients/1
# PATCH/PUT /nutrients/1.json
def update
respond_to do |format|
if #nutrient.update(nutrient_params)
format.html { redirect_to #nutrient, notice: 'Nutrient was successfully updated.' }
format.json { render :show, status: :ok, location: #nutrient }
else
format.html { render :edit }
format.json { render json: #nutrient.errors, status: :unprocessable_entity }
end
end
end
# DELETE /nutrients/1
# DELETE /nutrients/1.json
def destroy
#nutrient.destroy
respond_to do |format|
format.html { redirect_to nutrients_url, notice: 'Nutrient was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_nutrient
#nutrient = Nutrient.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def nutrient_params
params.require(:nutrient).permit(:name)
end
end
diaries_controller.rb
class DiariesController < ApplicationController
before_action :set_diary, only: [:show, :edit, :update, :destroy]
# GET /diaries
# GET /diaries.json
def index
#diaries = Diary.all
end
# GET /diaries/1
# GET /diaries/1.json
def show
end
# GET /diaries/new
def new
#diary = Diary.new
end
# GET /diaries/1/edit
def edit
end
# POST /diaries
# POST /diaries.json
def create
#diary = Diary.new(diary_params)
respond_to do |format|
if #diary.save
format.html { redirect_to #diary, notice: 'Diary was successfully created.' }
format.json { render :show, status: :created, location: #diary }
else
format.html { render :new }
format.json { render json: #diary.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /diaries/1
# PATCH/PUT /diaries/1.json
def update
respond_to do |format|
if #diary.update(diary_params)
format.html { redirect_to #diary, notice: 'Diary was successfully updated.' }
format.json { render :show, status: :ok, location: #diary }
else
format.html { render :edit }
format.json { render json: #diary.errors, status: :unprocessable_entity }
end
end
end
# DELETE /diaries/1
# DELETE /diaries/1.json
def destroy
#diary.destroy
respond_to do |format|
format.html { redirect_to diaries_url, notice: 'Diary was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_diary
#diary = Diary.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def diary_params
params.require(:diary).permit(:nutrient_id, :amount)
end
end
routes.rb
Rails.application.routes.draw do
resources :diaries
resources :nutrients do
collection do
get :search
end
end
_form.html.erb (for a new diary record)
<%= form_for(#diary) do |f| %>
<% if #diary.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#diary.errors.count, "error") %> prohibited this diary from being saved:</h2>
<ul>
<% #diary.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :nutrient_id %><br>
<%= f.number_field :nutrient_id %>
</div>
<div class="field">
<%= f.label :amount %><br>
<%= f.number_field :amount %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
There are several ways to resolve this, one the quickest and most likely the best approach to me would be to nest the diaries under nutrients, since diaries belongs_to :nutrients
resources :nutrients do
resources :diaries
collection do
get :search
end
end
This way your all your diaries path method would accept a #nutrient argument and your route would be like: /nutrients/4/diaries/1
So in your diaries_controller, you could have:
class DiariesController < ApplicationController
before_action :set_nutrient
def new
#diary = #nutrient.diaries.new
end
def create
#diary = #nutrient.diaries.new(diary_params) # you can safely remove the nutrient_id from the strong params
... remaining logic here
end
...
private
def set_nutrient
#nutrient ||= Nutrient.find(params[:nutrient_id])
end
# You cans skip/ignore this method, if you don't want to be too strict
def set_diary
#diary ||= #nutrient.diaries.find(params[:id])
end
end
Then in your view, you could then have:
<%= form_for([#nutrient, #diary]) do |f| %>
<% if #diary.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#diary.errors.count, "error") %> prohibited this diary from being saved:</h2>
<ul>
<% #diary.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :amount %><br>
<%= f.number_field :amount %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
As I mentioned, there are still other ways of doing this, as you could also use hidden_fields however, this seem to be the cleanest way to me.
If you don't always want your diaries routes to be nested, you could expect: [the list of actions that should not be nested, eg show], both on your before_action and your routes' resources :diaries. Hope I'm able to help or let me know other confusions you may encounter.

Nested resources in rails not saving

Ive setup some nested resources in Rails using the following:
resources :notes do
resources :comments
end
But even though /notes/1/comments/new will take me to a new comments page, it does not make the association of the note for the comment. I have included an note_id field in the comment but this does not get populate. Any tips?
Comments controller:
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
# GET /comments
# GET /comments.json
def index
#comments = Comment.all
end
# GET /comments/1
# GET /comments/1.json
def show
end
# GET /comments/new
def new
#comment = Comment.new
end
# GET /comments/1/edit
def edit
end
# POST /comments
# POST /comments.json
def create
#comment = Comment.new(comment_params)
respond_to do |format|
if #comment.save
format.html { redirect_to #comment, notice: 'Comment was successfully created.' }
format.json { render :show, status: :created, location: #comment }
else
format.html { render :new }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /comments/1
# PATCH/PUT /comments/1.json
def update
respond_to do |format|
if #comment.update(comment_params)
format.html { redirect_to #comment, notice: 'Comment was successfully updated.' }
format.json { render :show, status: :ok, location: #comment }
else
format.html { render :edit }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /comments/1
# DELETE /comments/1.json
def destroy
#comment.destroy
respond_to do |format|
format.html { redirect_to comments_url, notice: 'Comment was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
#comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit(:note_id, :comment)
end
end
Form code:
<%= form_for(#comment) do |f| %>
<% if #comment.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#comment.errors.count, "error") %> prohibited this comment from being saved:</h2>
<ul>
<% #comment.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :note_id %><br>
<%= f.text_field :note_id %>
</div>
<div class="field">
<%= f.label :comment %><br>
<%= f.text_area :comment %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
You should create your Comment like this in your controller:
class CommentsController < ApplicationController
before_action :set_comment, :set_note, only: [:show, :edit, :update, :destroy]
# Build your comment from your #note
# this sets all the association values correct (like ids)
def create
#comment = #note.comments.build(comment_params)
# etc...
end
def set_note
#note = Note.find(params[:note_id])
end
#...
end
So, using the #note.commments.build will help you on your issue. But of course, you need to query the #note using the note_id in the params hash.

Nested Form in Rails 4 not being rendered in view

Apologies if this has already been answered but I can't find anything that can help me. I am a newbie with Rails so please be gentle :D
I have been pulling my hair out trying to get nested forms working, I am sure I got nested forms working using Rails 3 and the railscasts demo last year, but Rails 4 is beating me.
Looking at the log, the query is being run to pull the data for the associated table, but nothing is rendered in the form.
I have read many web sites, but none have helped so far and I don't know where to start. The latest article I have followed is this http://www.createdbypete.com/articles/working-with-nested-forms-and-a-many-to-many-association-in-rails-4/
Still nothing being rendered in the view.
Where do I start debugging this, maybe my Rails install is broken?? But I am probably missing something crucial.
Thanks,
Royce
Edit - I have added some of the controllers and the view in question
surveys_controller.rb
class SurveysController < ApplicationController
before_action :set_survey, only: [:show, :edit, :update, :destroy, :answers]
# GET /surveys
# GET /surveys.json
def index
#surveys = Survey.all
end
# GET /surveys/1
# GET /surveys/1.json
def show
end
# GET /surveys/new
def new
#survey = Survey.new
end
# GET /surveys/1/edit
def edit
end
# POST /surveys
# POST /surveys.json
def create
#survey = Survey.new(survey_params)
respond_to do |format|
if #survey.save
format.html { redirect_to #survey, notice: 'Survey was successfully created.' }
format.json { render :show, status: :created, location: #survey }
else
format.html { render :new }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /surveys/1
# PATCH/PUT /surveys/1.json
def update
respond_to do |format|
if #survey.update(survey_params)
format.html { redirect_to #survey, notice: 'Survey was successfully updated.' }
format.json { render :show, status: :ok, location: #survey }
else
format.html { render :edit }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
# DELETE /surveys/1
# DELETE /surveys/1.json
def destroy
#survey.destroy
respond_to do |format|
format.html { redirect_to surveys_url, notice: 'Survey was successfully destroyed.' }
format.json { head :no_content }
end
end
def answers
#participants = Participant.all
#questions = #survey.questions
end
private
# Use callbacks to share common setup or constraints between actions.
def set_survey
#survey = Survey.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def survey_params
params.require(:survey).permit(:name,
:questions_attributes => [:id, :content,
:answers_attributes => [:id, :content, :participant_id]
])
end
end
participents_controller.rb
class ParticipantsController < ApplicationController
before_action :set_participant, only: [:show, :edit, :update, :destroy]
# GET /participants
# GET /participants.json
def index
#participants = Participant.all
end
# GET /participants/1
# GET /participants/1.json
def show
end
# GET /participants/new
def new
#participant = Participant.new
end
# GET /participants/1/edit
def edit
end
# POST /participants
# POST /participants.json
def create
#participant = Participant.new(participant_params)
respond_to do |format|
if #participant.save
format.html { redirect_to #participant, notice: 'Participant was successfully created.' }
format.json { render :show, status: :created, location: #participant }
else
format.html { render :new }
format.json { render json: #participant.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /participants/1
# PATCH/PUT /participants/1.json
def update
respond_to do |format|
if #participant.update(participant_params)
format.html { redirect_to #participant, notice: 'Participant was successfully updated.' }
format.json { render :show, status: :ok, location: #participant }
else
format.html { render :edit }
format.json { render json: #participant.errors, status: :unprocessable_entity }
end
end
end
# DELETE /participants/1
# DELETE /participants/1.json
def destroy
#participant.destroy
respond_to do |format|
format.html { redirect_to participants_url, notice: 'Participant was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_participant
#participant = Participant.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def participant_params
params.require(:participant).permit(:name)
end
end
application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
end
answers.html.erb
<h1><%= #survey.name %> Answers</h1>
<%= form_for(#survey) do |f| %>
<% #participants.each do |participant| -%>
<h3><%= participant.name %></h3>
<table>
<thead>
<tr>
<td>Questions</td>
<td>Answer</td>
</tr>
</thead>
<tbody>
<% #questions.each do |question| -%>
<tr>
<td><%= question.content %></td>
<td>
<%= f.fields_for :questions, question do |q| -%>
<%= q.fields_for :answers, question.answers.find_or_initialize_by(participant: participant) do |a| -%>
<%= a.text_area :content %>
<%= a.hidden_field :participant_id, participant.id %>
<% end -%>
<% end -%>
</td>
</tr>
<% end -%>
</tbody>
</table>
<% end -%>
<div class="actions">
<%= f.submit %>
</div>
<% end -%>
As you're new with Rails, let me explain how nested forms work for you!
--
Nested
Nested forms are not actually nested at all - they are associative forms.
You must remember that Rails (by virtue of being built on Ruby) is an object orientated framework. OOP (object orientated programming) is not just a buzzword - it's a fundamental core construction for your application & how it hands input / execution.
The problem many people have is they don't realize the true nature of Rails, and consequently become confused about how its many features work. If you appreciate that everything you do in Rails should be constructed around objects, life gets much simpler!
--
Form
With this in mind, you can begin to appreciate the role of objects throughout Rails, to the degree that you need to build / invoke objects for every element of your Rails application, including your form:
#app/models/survey.rb
Class Survey < ActiveRecord::Base
has_many :questions
accepts_nested_attributes_for :questions
end
#app/controllers/surveys_controller.rb
Class SurveysController < ApplicationController
def new
#survey = Survey.new
#survey.questions.build #-> very important
end
end
#app/views/surveys/new.html.erb
<%= form_for #survey do |f| %>
...
<%= f.fields_for :questions do |q| %>
<%= q.text_field :title %>
<% end %>
<%= f.submit %>
<% end %>
This should create a form which allows you to pass associative data through to your child model. There are several important elements to consider:
You need to include accepts_nested_attributes_for in your "parent" model
You need to build your associative objects
You need to populate your form with the relative objects
By following this simple pattern, you'll be able to populate the nested form that you wish to show in the view
Try to use the following code:
<%= f.fields_for :questions do |q| -%>
<%= q.fields_for :answers, q.object.answers.find_or_initialize_by(participant: f.object.participant) do |a| -%>
<%= a.text_area :content %>
<%= a.hidden_field :participant_id, participant.id %>
<% end -%>
<% end -%>
and make sure that you render to answers.html.erb, you have accepts_nested_attributes_for :questions in survey.rb file, and accepts_nested_attributes_for :answers in question.rb file
Have you got accepts_nested_attributes_for :question in your survey model? And the same for the answer model?

Strong params: No mass assignment error message when parameter not on whitelist is passed onto database

I've newly upgraded to rails 4.0.1
Simple enough experiment to test the new strong params:
class StatusesController < ApplicationController
before_action :set_status, only: [:show, :edit, :update, :destroy]
# GET /statuses
# yersh GET /statuses.json
def index
#statuses = Status.all
end
# GET /statuses/1
# GET /statuses/1.json
def show
# GET thingy
end
# GET /statuses/sdfnew
def new
#status = Status.new
end
# GET /statuses/1/edit
def edit
end
# POST /statuses
# POST /statuses.json
def create
#status = Status.new(status_params)
respond_to do |format|
if #status.save
format.html { redirect_to #status, notice: 'Status was successfully created.' }
format.json { render action: 'show', status: :created, location: #status }
else
format.html { render action: 'new' }
format.json { render json: #status.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /statuses/1
# PATCH/PUT /statuses/1.json
def update
respond_to do |format|
if #status.update(status_params)
format.html { redirect_to #status, notice: 'Status was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #status.errors, status: :unprocessable_entity }
end
end
end
# DELETE /statuses/1
# DELETE /statuses/1.json
def destroy
#status.destroy
respond_to do |format|
format.html { redirect_to statuses_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_status
#status = Status.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def status_params
params.require(:status).permit(:nothing)
end
As you can see, the only parameter I have whitelisted is something called 'nothing'. So here's my new status view and form:
<%= simple_form_for(#status, html: { class: "form-group"}) do |f| %>
<% if #status.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#status.errors.count, "error") %> prohibited this status from being saved:</h2>
<ul>
<% #status.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.input :content, class: "form-control" %><br>
</div>
<div class="form-actions">
<%= f.button :submit, class: "btn btn-success" %>
</div>
<% end %>
As you can see, it has one input, for a parameter called content. I enter data and submit the form, and I am routed to get a flash saying 'Status was successfully created.', and routed to the status. Now, the content field is empty on this status (note the second column from the left):
24||2013-11-29 16:34:01.389499|2013-11-29 16:34:01.389499|
So this means the status_params method did do its job of stopping 'content' from being written to the database, but the damn thing is still created, albeit with an empty 'content' entry. I want a mass-assignment error, like in the good old days of attr_accessor. How can I get this behavior? I wish to stop a status being created if one of its attributes is not white listed?
Also, just venting here, but does anyone else think this whitelist strong params thing is utterly, utterly, utterly vile? Loved attr_access to bits, it was well organised (models contained everything to do with models, like they should), it was easy and not fiddly, and you could glance at your model files to see what attributes they have. No, when I want to verify what attributes a model has I need to fire up my rails console and run
Status.column_names
Urgh it's all just so hideous. Is there a chance it could be changed back? For nutjobs who want to have their model behavior in their controllers there should be gem for this. To overhaul rails like this, and not add backward functionality add the very least, is just rude.
This question is still open! I understand this behaviour does not happen in production, so that's great, but I'd still like to get a mass-assignment error for debugging purposes in the development environment, as well as the console message!
According to this source you can configure this behavior:
initializer "strong_parameters.config", :before => "action_controller.set_configs" do |app|
ActionController::Parameters.action_on_unpermitted_parameters = app.config.action_controller.delete(:action_on_unpermitted_parameters) do
(Rails.env.test? || Rails.env.development?) ? :log : false
end
end
Try setting in config/environments/development.rb:
config.action_controller.action_on_unpermitted_parameters = false
I haven't tried it but there definitely should be some way.

Resources