params.require().permit does not work as expected - ruby-on-rails

I have this controller
class PeopleController < ApplicationController
def new
#person = Person.new
#person.phones.new
end
# this is the action that gets called by the form
def create
render text: person_params.inspect
# #person = Person.new(person_params)
# #person.save
# redirect_to people_path
end
def index
#person = Person.all
end
private
def person_params
params.require(:person).permit(:name, phones_attributes: [ :id, :phone_number ])
end
end
and this view
<%= form_for :person, url: people_path do |f| %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<%= f.fields_for :phones do |f_phone| %>
<div class="field">
<p>
<%= f_phone.label :phone_number %><br />
<%= f_phone.text_field :phone_number %>
</p>
</div>
<% end %>
<p>
<%= f.submit %>
</p>
<% end %>
When I fill out both form fields and hit "Save Person" I only get {"name"=>"foo"} - the phone number seems to vanish.
However, when I change phones_attributes to phones I get {"name"=>"foo", "phones"=>{"phone_number"=>"123"}} (this would however cause problems with the create function.
What's wrong here?
Please note that this question is strongly related to that one: accepts_nested_attributes_for: What am I doing wrong as well as to this posting: https://groups.google.com/forum/#!topic/rubyonrails-talk/4RF_CFChua0

You don't have #phones defined in the controller:
def new
#person = Person.new
#phones = #person.phones.new
end

Finally found the problem. In the view there should be
<%= form_for #person, url: people_path do |f| %>
Instead of
<%= form_for :person, url: people_path do |f| %>
#phron said that already here:
accepts_nested_attributes_for: What am I doing wrong

Related

Can't insert data to db in ruby on rails

I just learn RoR and confuse now how to insert data to db. Here's my code:
book_insert.html.erb
<%= content_for :helloworld do %>
<%= form_tag("/insert", method: "post") do %>
<%= label_tag(:title, "Title") %>
<%= text_field_tag(:title) %><br>
<%= label_tag(:price, "Price") %>
<%= number_field_tag(:price) %><br>
<%= label_tag(:subject_id, "Subject ID") %>
<%= number_field_tag(:subject_id) %><br>
<%= label_tag(:description, "Description") %>
<%= text_field_tag(:description) %><br>
<br>
<%= submit_tag("Submit") %>
<% end %>
<% end %>
book_controller.rb
class BookController < ApplicationController
def insert
#book = Book.new(book_params)
#book.save
render :book_page
end
def book_params
params.require(:books).permit(:title, :price, :subject_id, :description)
end
def showinsert
render :book_insert
end
end
It returns error:
Completed 400 Bad Request in 4ms (ActiveRecord: 0.0ms)
ActionController::ParameterMissing (param is missing or the value is
empty: books):
Please help. Thanks
form_tag normally used to submit non-model actions to the mapped controller#action. You probably need to use form_for and its corresponding helpers inside the form
<%= content_for :helloworld do %>
<%= form_for Book.new, url: "/insert", method: "post" do |f| %>
<%= f.label :title %>
<%= f.text_field :title %><br>
<%= f.label :price %>
<%= f.number_field :price %><br>
<%= f.label :subject_id %>
<%= f.number_field :subject_id %><br>
<%= f.label :description %>
<%= f.text_field :description %><br>
<br>
<%= f.submit "Submit" %>
<% end %>
<% end %>
With the above code, the params would be passed inside :book => {} hash, so you need to change the book_params to below
def book_params
params.require(:book).permit(:title, :price, :subject_id, :description)
end #^
The params.require method requires that the key books is present in the hash - if not it raises an ActionController::ParameterMissing exception.
To nest inputs you need to name them accordingly:
<%= form_tag("/insert", method: "post") do %>
<%= label_tag("Title") %>
<%= text_field_tag("books[title]") %><br>
<%= label_tag("Price") %>
<%= number_field_tag("books[price]") %
...
<%= submit_tag("Submit") %>
<% end %>
This will give the params hash:
{ books: { title: 'Life & Times of Michael K', price: 99 } }
However thats pretty tedious. A better way is to use the forms helpers and setup your routes and controller according to the conventions:
# config/routes.rb
resources :books
# app/views/books/new.html.erb
<%= form_for(#book) do |f| %>
<div class="field">
<%= f.label :title %>
<%= f.text_field :title %>
</div>
# ...
<%= f.submit %>
<% end %>
# app/controllers/books_controller.rb
class BooksController < ApplicationController
# this renders the form to create a new book
# GET /books/new
def new
#book = Book.new
end
# In Rails its called create - not insert
# POST /books
def create
#book = Book.new(book_params)
if #book.save
redirect_to #book
else
render :new
end
end
# This is the path to show a book
# its also where we redirect after creating the book
# GET /books/:id
def show
#book = Book.find(params[:id])
end
# ...
private
def book_params
# note thats its book singular - not plural
params.require(:book).permit(:title, :price, :subject_id, :description)
end
end
You should do book in the book_params method instead of books:
def book_params
params.require(:book).permit(:title, :price, :subject_id, :description)
end

NameError in Controller#new in view in ruby on rails on windows

I am currently doing a CRUD, i am now in part of create method but I'm encountering when I load the new method(this is where my form is) NameError in Products#new
Question: Is my products_create_path correct? This is the action after I send the form into create method
New file
Add New Item
<%= form_for :product, url: products_create_path do |f| %>
<p>
<%= f.label :Name %><br>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :Size %><br>
<%= f.text_area :description %>
</p>
<p>
<%= f.label :Price %><br>
<%= f.text_field :price %>
</p>x
<p>
<%= f.submit :Submit %>
</p>
<% end %>
<%= link_to 'BACK', products_path %>
Routes
Rails.application.routes.draw do
resources :products
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
Controller
class ProductsController < ApplicationController
def index
#product = Product.all.order('created_at DESC')
end
def show
#post = Product.find(params[:id])
end
def new
#product = Product.new
end
def create
#post = Product.new(post_params)
if #post.save
redirect_to (products_path)
else
redirect_to('new')
end
end
private
def post_params
params.require(:product).permit(:name, :size, :price)
end
end
You don't need to give url in form_for tag. Rails internally redirect to path depends on in presence of id value.
Change form_for tag to this:
<%= form_for #product do |f| %>
So in your form_for tag, object (#product) has value for id field, then rails will submit the form to update routes else it will submit the form to create routes.
In your form change :description to :size
and change
<%= form_for :product, url: products_create_path do |f| %>
to
<%= form_for #product do |f| %>
products_create_path is not correct and you don't need it either. Your form should be <%= form_for(#product) do |f| %>
It should be:
<%= form_for :product, url: products_path do |f| %>
You can check your routes by using this command:
rake routes
Or find more information from here.
Hope I can help.
change your form_tag to
<%= form_for #post, :url => new_product_path do |f| %>
or
<%= form_for #product do |f| %>

rails 4 - param is missing or the value is empty: projecttype

A newby to rails (I am building an app to learn rails) and run in to an issue I can't find a solution to (while following the getting started guide). I have studied the guides and similar questions
This is my code:
class ProjecttypesController < ApplicationController
def index
#projecttypes = Projecttype.all
end
def show
#projecttype = Projecttype.find(params[:id])
end
def new
end
def create
#projecttype = Projecttype.new(projecttype_params)
#projecttype.save
redirect_to #projecttype
end
private
def projecttype_params
params.require(:projecttype).permit(:name, :image, :url)
end
end
The form:
<%= form_for :projecttypes, url: projecttypes_path do |f| %>
<p>
<%= f.label 'Project type' %>
<%= f.text_field :projecttype %>
</p>
<p>
<%= f.label :name %>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :image %>
<%= f.file_field :image %>
</p>
<p>
<%= f.label :url %>
<%= f.url_field :url %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
What am I doing wrong?
Perhaps important... when I use this...
def create
render plain: params[:projecttype].inspect
end
It returns 'nil'.
Thanks for your help
Your code should be like this
def new
#projecttype = Projecttype.new
end
def create
#projecttype = Projecttype.create(projecttype_params)
redirect_to #projecttype
end
and use this for form
<%= form_for #projecttype do |f| %>
In your
controller file
def new
#projecttype = Projecttype.new
end
and then in your form
<%= form_for #projecttype do |f| %>

undefined method `reviews' for nil:NilClass

I'm trying to create a reviews model for company pages. For this I have:
Models
user.rb
has_many :reviews
class Review < ActiveRecord::Base
belongs_to :user
belongs_to :company
end
class Company < ActiveRecord::Base
has_many :reviews
end
My reviews controller is:
def create
#company = Company.find_by_slug(params[:id])
#review = #company.reviews.create(params[:review])
#review.save
redirect_to company_path(#company)
end
and I have this code in the company show page:
<% #company.reviews.each do |review| %>
<p>
<strong>Title:</strong>
<%= review.title %>
</p>
<p>
<strong>Avantage:</strong>
<%= review.avantage %>
</p>
<p>
<strong>Inconvenient:</strong>
<%= review.inconvenient %>
</p>
<% end %>
</br>
<%= form_for([#company, #company.reviews.build]) do |f| %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :avantage %><br>
<%= f.text_area :avantage %>
</div>
<div class="field">
<%= f.label :inconvenient %><br>
<%= f.text_area :inconvenient %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
However, when I go to a specific company page and try to create a review for this company I'm getting this error message undefined method reviewsfor nil:NilClass
Instead of #company = Company.find_by_slug(params[:id]) use this code #company = Company.friendly.find(params[:company_id])
There are a couple of things you may find useful:
If you're using Rails 4, you may encounter a further problem. In the third line of your create method, you are using unsecure params directly in a .create call. Check out the Rails Guide page on "strong params".
If you implement strong parameters as mentioned above, you should probably deliberately omit the company_id field from the list of permitted params.
Assuming your users are allowed to write a review for any company in your system, it might be simpler for you to embed the company_id as a hidden field in your form. This would allow you to also simplify the controller method. For example:
# _form.html.erb
<%= form_for(#review) do |f| %>
<%= f.hidden_field :company_id, value: #company.id %>
...bla bla bla
<% end %>
Then, in your reviews_controller...
# reviews_controller.rb
def create
#review = Review.new(approved_params)
if #review.save
flash[:success] = 'Review created!'
else
flash[:error] = "Review wasn't saved"
end
#company = #review.company
redirect_to #company
end
def approved_params
params.require(:review).permit(:title, :avantage, :inconvenient, :company_id)
end
In your companies_controller, you should add this to your show method
# companies_controller.rb
def show
#company = Company.find(params[:id]
# add this line below...
#review = Review.new
end
I hope this helps.

Getting from controller to associated model

I can't get along with saving Students with one POST when i"m saving Project.
My Projects controller looks like:
class ProjectsController < ApplicationController
def index
#projects = Project.all
end
def new
#project = Project.new
3.times do
student = #project.students.build
end
end
def create
#project = Project.new(project_params)
#project.status = "Waiting"
# I'm not sure about these lines
#project.students.each do |student|
student = Student.new(params[:name])
end
#project.save!
redirect_to projects_path
end
private
def project_params
params.require(:project).permit(:name, :lecturer)
end
end
And a new_project view looks like:
<h1>Creating new project...</h1>
<%= form_for #project, url: projects_path do |f| %>
<p>
<%= f.label :name %>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :lecturer %>
<%= f.text_field :lecturer %>
</p>
<p>
<%= f.fields_for :students do |s| %>
<%= s.label :name %>
<%= s.text_field :name %>
<% end %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
And my question is how to save Project and Students (assigned to it) using one form?
First, your project_params method isn't allowing the students' names to be submitted. Try something like this:
def project_params
params.require(:project).permit(:name, :lecturer, students_attributes: [ :name ] )
end
Next, in your Project model you'll need the line
accepts_nested_attributes_for :students
(You might have put it there already - but if you didn't, you'll need to.)
Now that that's done, you shouldn't need these lines in your Project#create method:
#project.students.each do |student|
student = Student.new(params[:name])
end
Because your project can now accept nested attributes for students, they should be created automatically with the project when you save it.

Resources