Nested Forms with Strong Parameters; object_attribute method not available? - ruby-on-rails

This example is kind of cliche. I am following the railscasts episode #196 (http://railscasts.com/episodes/196-nested-model-form-revised?autoplay=true) for double nested forms.
The error I get is that my accepts_nested_attributes_for command is not generating an answers_attributes for strong parameters.
Models:
class Survey < ActiveRecord::Base
has_many :questions
accepts_nested_attributes_for :questions
end
class Question < ActiveRecord::Base
belongs_to :survey
has_many :answers
has_many :users, through: :answers
accepts_nested_attributes_for :answers
end
class Answer < ActiveRecord::Base
belongs_to :question
belongs_to :user
end
Then my surveys controller:
class SurveysController < ApplicationController
def index
#survey = current_user.surveys
end
def new
#survey = Survey.new
#question = #survey.questions.build # the nested form won't show up if I don't
#answer = #question.answers.build #Not sure if I need this line. doesn't work either way.
end
def create
#survey = Survey.new(survey_params)
if #survey.save
redirect_to #survey, notice: "Survey successfully created."
else
render 'new'
end
end
# rest.. show, edit, update, destroy
private
def survey_params
params.require(:survey).permit!
end
#def survey_params
#params.require(:survey).permit(:user_id, :name, { questions_attributes: [:_destroy, :id, :survey_id, :content, { answers_attributes: [:_destroy, :id, :content, :user_id, :question_id]}]})
#end
end
The issue I'm having is this (empty form submit). When I run my real code, I get this:
{"utf8"=>"✓", "authenticity_token"=>"[token]=", "survey"=>{"user_id"=>"1", "name"=>"test", "questions_attributes"=>{"0"=>{"content"=>"test", "_destroy"=>"0"}}, "answers"=>{"content"=>"test", "_destroy"=>"0"}}, "commit"=>"Create", "action"=>"create", "controller"=>"surveys"}
Unpermitted attributes: answers
Then when I run the permit! method to test a force though I get this:
unknown attribute: answers
Rails should be looking for answers_attributes, not answers. That makes me think it's not recognizing the model. So, here is the schema.
create_table "questions", force: true do |t|
t.integer "survey_id"
t.string "content"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "answers", force: true do |t|
t.integer "question_id"
t.string "content"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
end
Let me know if you have any ideas on how to fix my error of somehow telling rails to look for answers instead of answers_attributes.
UPDATE: Here is my form.
<%= form_for #survey do |f| %>
<%= f.label :user_id %>
<%= f.collection_select :user_id, User.all, :id, :email, {}, { :multiple => false } %><br>
<%= f.text_field :name, placeholder: "Survey name"%>
<%= f.fields_for :questions do |builder| %>
<%= builder.label :content, "Question 1"%>
<%= builder.text_area :content %>
<%= builder.check_box :_destroy %>
<%= builder.label :_destroy, "Remove Question" %>
<%= f.fields_for :answers do |builder| %>
<%= builder.text_field :content, placeholder: "Answer 1" %>
<%= builder.check_box :_destroy %>
<% end %>
<% end %><br>
<%= f.submit "Create", :class => "btn btn-large btn-warning" %>
<% end %>

The solution was an oversight on the forms. I used...
<%= f.fields_for :questions do |builder| %>
...to build the association under the survey and then mistakenly used...
<%= f.fields_for :answers do |builder| %>
...to build the answers under question. I needed to change the f variable so it shoulder have been something like this:
<%= builder.fields_for :answers do |x| %>
So, it was looking for answers under survey instead of under questions. Thanks guys.

Related

Adding nested json in tables - rails

I am new to ruby on rails and I am trying to store nested json in the table.
json:
articles: {
title: "abc",
text: "a",
address: {
flat: "abc",
city: "bang"
}
}
Migrations:
class CreateArticles < ActiveRecord::Migration[5.2]
def change
create_table :articles do |t|
t.string :title
t.text :text
t.string :address
t.timestamps
end
end
end
class CreateAddresses < ActiveRecord::Migration[5.2]
def change
create_table :addresses do |t|
t.string :flat
t.string :city
t.timestamps
end
end
end
models:
class Article < ApplicationRecord
has_one :address
accepts_nested_attributes_for :address
end
class Address < ApplicationRecord
end
controller:
class ArticlesController < ApplicationController
def create
#article = Article.new(params.require(:article).permit(:title, :text, :address))
#article.save
redirect_to #article
end
def show
#article = Article.find(params[:id])
end
end
form(new.html.erb):
<%= form_with scope: :article, url: articles_path, local: true do |form| %>
<p>
<%= form.label :title %><br>
<%= form.text_field :title %>
</p>
<p>
<%= form.label :text %><br>
<%= form.text_area :text %>
</p>
<%=form.fields_for :address do |a| %>
<div>
<%=a.label :flat%><br>
<%= a.text_field :flat%><br>
<%=a.label :city%><br>
<%= a.text_field :city%>
</div>
<%end%>
<p>
<%= form.submit %>
</p>
I am not able to store the adrress to the table. address is always saved as nil. Can anyone guide me if what i am doing wrong. I want to parse the json to the table and store the json as string. Updated the question with controller and form that i am using.
When you want to permit nested attributes you do specify the attributes of nested object within an array. Pls, try this one #article = params.require(:articles).permit(:text, :title, :address =>[:flat, :city])
Rails has a very good documentation pls take a look https://api.rubyonrails.org/classes/ActionController/Parameters.html#method-i-permit

Unpermitted parameter: ROR

I am new in ror and when I submit my form:
<%= form_for :project, url: projects_path, html: {id:'form'} do |f| %>
<%= f.text_field :text, placeholder: 'Новая задача' %>
<%= link_to 'Отмена', '', id:'cancel_link' %>
<%= link_to 'Отправить', projects_path, id:'submit_link' %>
<% end %>
Have error:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"OR2HWCi3zVz9gB5VAmnzbEuzIwFGE58JlLrWQdNcws6FVTzqh5Cu0zvUJTUEv2O/sCvU9HuadJYr3mfA40ehGA==", "project"=>{"text"=>"NEW ITEM"}} Unpermitted parameter: :text
Have two models:
class Project < ApplicationRecord
has_many :todos
validates :title, presence: true
accepts_nested_attributes_for :todos
end
class Todo < ApplicationRecord
belongs_to :project, required: false
end
The Todo model has a text attribute in which our todo should be located
Controller
class ProjectsController < ApplicationController
def index
#projects = Project.all
end
def create
#project = Project.new(project_params)
if #project.save
redirect_to root_path
end
end
def update
end
private
def project_params
params.require(:project).permit(:title, todos_attributes: [:id, :text])
end
end
Project db
class CreateProjects < ActiveRecord::Migration[5.2]
def change
create_table :projects do |t|
t.string :title
t.string :todos
t.timestamps
end
Todo db
class CreateTodos < ActiveRecord::Migration[5.2]
def change
create_table :todos do |t|
t.text :text
t.boolean :isCompleted
t.integer :project_id
t.timestamps
end
I'm requesting the todo attributes using accepts_nested_attributes_for: todos, the controller is also registered on the guides, in project_params I request todos_attributes. But when sending a form to the database, the value is text. He does not save in db. Can u help please
In order to save text field in Todo model, you have to create nested form. Use nested_form gem for this purpose.
A vague example to show how it works:
<%= nested_form_for :project, url: projects_path, html: { id: 'form' } do |f| %>
<%= f.text_field :title, placeholder: 'Новая задача' %>
<%= f.fields_for :todos do |todo_form| %>
<%= todo_form.text_field :text %>
<%= todo_form.link_to_remove "Remove this todo" %>
<% end %>
<p><%= f.link_to_add "Add a todo", :todos %></p>
<%= link_to 'Отмена', '', id:'cancel_link' %>
<%= link_to 'Отправить', projects_path, id:'submit_link' %>
<% end %>
In controller, to have the functionality of removing a todo in case of editing a project:
def project_params
params.require(:project).permit(:title, todos_attributes: [:id, :text, _destroy])
end
In the migration CreateProjects < ActiveRecord::Migration[5.2], I do not think that you require todos as a string.
The form which you created is wrong, you need to create a nestead_form
It is giving you and Unpermitted parameter error because the text is not a field of project model you can check this on your migration file. You need to change it to title because the title is the field of project model.
And for to create a nested form you need to do some changes in your form
<%= form_for :project, url: projects_path, html: {id:'form'} do |f| %>
<%= f.text_field :title, placeholder: 'Новая задача' %>
<%= f.fields_for :todos do |todo| %>
<%= f.text_field :text %>
<% end %>
<%= link_to 'Отмена', '', id:'cancel_link' %>
<%= link_to 'Отправить', projects_path, id:'submit_link' %>
<% end %>

Nested form fields not showing in polymorphic association

Hi I have a polymorphic association with for a Document model for storing document uploads. I'm trying to submit the document attributes as a nested attribute via the associated model.
However, when I load the form, the nested field does not show. What am I missing?
Schema:
create_table "documents", force: :cascade do |t|
t.json "links"
t.integer "linkable_id"
t.string "linkable_type"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "documents", ["linkable_type", "linkable_id"], name: "index_documents_on_linkable_type_and_linkable_id", using: :btree
Models:
class Document < ActiveRecord::Base
belongs_to :linkable, polymorphic: true
belongs_to :user
belongs_to :company
mount_uploaders :links, DocUploader
end
class CustomerPlan < ActiveRecord::Base
has_many :documents, as: :linkable
accepts_nested_attributes_for :documents
end
Controller:
class CustomerPlanController < ApplicationController
def new
#customer_plan = current_company.customer_plans.build
end
def create
#customer_plan = current_company.customer_plans.build(customer_plan_params)
if #customer_plan.save
redirect_to #customer_plan, notice: 'Customer plan was successfully created.'
else
render :new
end
end
private
def cusomter_plan_params
params.require(:cusomter_plan_params).permit(:date, :name, :plan_type,
documents_attributes: [:id, links: []])
end
end
Form:
<%= simple_nested_form_for #stock_plan, :html => { :multipart => true } do |f| %>
<%= f.error_notification %>
<%= f.input :date %>
<%= f.input :name %>
<%= f.input :plan_type %>
<%= f.simple_fields_for :documents do |d| %>
<p><b>Upload here:</b></p>
<%= d.file_field :links, multiple: true %>
<br>
<% end %>
<%= f.button :submit%>
<% end %>

Add categories for posts - Rails

Could you please help with understanding why categories does not working in a right way? So I read quite a lot manuals about, and did not find how to resolve it
I created migration for category
class CreateCategories < ActiveRecord::Migration
def change
create_table :categories do |t|
t.string :name
t.text :description
t.integer :count
t.timestamps null: false
end
end
end
And added for posts new field - category
Then created model for category
class Category < ActiveRecord::Base
has_many :posts
end
Edit post model
class Post < ActiveRecord::Base
acts_as_ordered_taggable
belongs_to :category
validates :title, presence: true
validates :category, presence: true
..
end
Created template
<%= form_for #post do |f| %>
<p>
<%= f.label :title %> <br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :category %>
<%= f.select :category, Category.all.collect {|c| [c.name, c.name]} %>
</p>
<% end %>
Edited a bit post controller
def update
#post = Post.find(params[:id])
if #post.update(params[:post].permit(:title, :thumbnail, :body, :description, :tag_list, :#post.category))
redirect_to #post
else
render 'edit'
end
end
change this line in your controller:
if #post.update(params[:post].permit(:title, :thumbnail, :body, :description, :tag_list, :category_id))
I changed
:#post.category
to
:category_id
This passes a symbol to the permit method to allow the request parameter for the category

rails 4 mass assignment error with protected_attributes gem

I'm trying to add a user profile sub module to a user module but having some problems.
Routes:
resources :users do
resources :userprofiles
end
userprofiles_controller.rb:
class UserprofilesController < ApplicationController
def edit
#user = current_user
#user.UserProfile ||= UserProfile.new
#userprofile = #user.UserProfile
end
def update
#user = current_user
#user.UserProfile ||= UserProfile.new
#userprofile = #user.UserProfile
if #userprofile.update_attributes(:userprofile => params[:userprofile])
redirect_to #user
flash[:notice] = "Changes saved."
else
render 'edit'
flash[:notice] = "Error."
end
end
end
user_profile.rb:
class UserProfile < ActiveRecord::Base
attr_accessible :first_name, :last_name, :summary
belongs_to :user
end
Error:
Can't mass-assign protected attributes for UserProfile: userprofile
Line:
if #userprofile.update_attributes(:userprofile => params[:userprofile])
EDIT
Form:
<%= form_for([#user, #userprofile], url: user_userprofile_path(#user, #userprofile)) do |form| %>
<%= form.label :first_name %>
<%= form.text_field :first_name %>
<%= form.label :last_name %>
<%= form.text_field :last_name %>
<%= form.label :summary %>
<%= form.text_area :summary %>
<%= form.submit "Update", class: "btn btn-block btn-primary" %>
<% end %>
Table:
create_table "user_profiles", force: true do |t|
t.string "last_name"
t.string "first_name"
t.text "summary"
t.integer "user_id", null: false
t.datetime "created_at"
t.datetime "updated_at"
end
You just want
#userprofile.update_attributes(params[:userprofile])
That's a hash with keys :first_name, :last_name, and :summary, which are allowed attributes. When you try to update :userprofile => params[:userprofile], the model checks to see if the key :userprofile is allowed - and it isn't.
I also had this problem. The issue is that you still have attr_accessible in your model controller. Since you don't need them anymore with Rails 4 remove them, add your strong parameters to the controller, and you'll be able to mass-assign without issue.

Resources