I am getting Forbidden Attributes Error even though I have used strong parameters in Rails. I have two models: Posts and Categories.
Here is my Post Controller:
class PostsController < ApplicationController
def index
#posts=Post.all
end
def new
#post=Post.new
#category=Category.all
end
def create
#post = Post.new(params[:post])
if #post.save
redirect_to posts_path,:notice=>"Post saved"
else
render "new"
end
end
def allowed_params
params.require(:post).permit(:title, :body, :category_id)
end
end
And here is my view for posts/new:
<%= form_for #post do |f| %>
<p>
<%= f.label :title %></br>
<%= f.text_field :title%><br/>
</p>
<p>
<%= f.label :body %></br>
<%= f.text_area :body%><br/>
</p>
<p>
<%= f.select :category_id, Category.all.collect{|x| [x.name,x.id]},{:include_blank =>"Select one"}%><br/>
</p>
<p>
<%= f.submit "Add Post" %>
</p>
<% end %>
But I am still getting Error.
You need to use allowed_params instead of params[:post]:
#post = Post.new(allowed_params)
Related
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
I have a 'post' controller in that I have two variable title and body which I am passing through strong parameters.But I need to use two other variable which are path and name which are in different model name 'Document'..And also I am saving the content in database ..but unable to do so..getting this error view [posts/_form.html.erb]
undefined method `name' for #
[posts_controller]
class PostsController < ApplicationController
before_action :authenticate_user!
def index
#posts = Post.user_post(current_user).order('created_at DESC').paginate(:page => params[:page], :per_page => 5)
end
def new
#post = Post.new
end
def show
#post = find_params
end
def create
#post = Post.create(post_params)
#post.user = current_user
if #post.save
redirect_to #post
else
render 'new'
end
end
def edit
#post = find_params
end
def update
#post = find_params
if #post.update(post_params)
redirect_to #post
else
render 'edit'
end
end
def destroy
#post = find_params
#post.destroy
redirect_to posts_path
end
private
def post_params
params.require(:post).permit(:title, :body)
Document.new(params,:files=>[])
end
def find_params
Post.find(params[:id])
end
end
[post/_form.html.erb]
<%= form_for #post,html: { multipart: true } do |f| %>
<% if #post.errors.any? %>
<div id="errors">
<h2><%= pluralize(#post.errors.count, "error") %> prevented this post from saving:</h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.label :title %><br>
<%= f.text_field :title %><br>
<br>
<%= f.label :body %><br>
<%= f.text_field :body %><br>
<br>
<%= f.label :name %> <br>
<%= f.text_field :name %><br>
<br>
<br>
<%= f.label :path %><br>
<%= f.file_field :path %><br>
<%= f.submit %>
<% end %>
[document.rb]
class Document < ActiveRecord::Base
validates :name, presence: true
validates :path, presence: true
validates :resource_type, presence: true
validates :resource_id, presence: true
mount_uploader :path, PathUploader
validates :name, presence: true
# def self.abc
# params.permit(:name,:path)
# end
def initialize(params,file)
params=file[:name]
#params.permit(name =>:name,path =>:path)
end
end
undefined method `name' for #
You're referencing a non-existent attributes for your Post form:
<%= form_for #post,html: { multipart: true } do |f| %>
<%= f.label :title %><br>
<%= f.text_field :title %><br>
<br>
<%= f.label :body %><br>
<%= f.text_field :body %><br>
<%= f.submit %>
<% end %>
Remove :name & :path references.
--
If you want to pass "extra" attributes to another model, you need to use accepts_nested_attributes_for or set the params separately to your "primary" model:
#app/models/post.rb
class Post < ActiveRecord::Base
has_many :documents
accepts_nested_attributes_for :documents
end
#app/models/document.rb
class Document < ActiveRecord::Base
belongs_to :post
end
This will allow you to pass the documents as "nested" attributes of your Post model:
#app/controllers/posts_controller.rb
class PostsController < ApplicationController
def new
#post = Post.new
#post.documents.build
end
def create
#post = Post.new post_params
#post.save
end
private
def post_params
params.require(:post).permit(:title, :body, documents_attributes: [:name, :path])
end
end
#app/views/posts/_form.html.erb
<%= form_for #post do |f| %>
<%= f.text_field :title %>
<%= f.text_area :body %>
<%= f.fields_for :documents do |d| %>
<%= d.text_field :name %>
<%= d.text_field :path %>
<% end %>
<%= f.submit %>
<% end %>
So undefined method on a model will indicate that, well, the method doesn't exist on the model. Want to see a model's methods? Post.methods. However, in this example, the column name is not defined on the model., and you're trying to tell Post that it has a name. What you need to do is nest your parameters.
While there is a ton of cleaning up that might want to focus on first, your answer is found in the accepts_nestable_attributes_for class methods, as shown here, http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html, and strong_params documentation as shown here, http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html
In your case, you want to create a new document from a post. Your permitted params hash will look like this,
params.require(:post).permit(:title, :body, :document_attributes => [:name])
Ensure that document_attributes is singular; if a person has_many pets (for example), then you'd have pets_attributes.
In your form, something that often trips people up is the builder.
<%= form_for #post do |f| %>
<%= f.text_field :title %>
<%= f.text_field :body %>
<%= f.fields_for #post.document do |document_field| %>
<%= document_field.text_field :name %>
<% end %>
<%= f.submit %>
<% end %>
Make sure that you're telling ERB that <%= f.fields_for %>, not just <% f.fields_for %>.
I'm trying to add a reviews on my single product page. But when I click Submit - It takes me to the /products.1 page, instead of /products/1
class CommentsController < ApplicationController
def create
#product = Product.find(params[:product_id])
#comment = #product.comments.new(comment_params)
#comment.user = current_user
#comment.save
redirect_to products_path(#product)
end
def destroy
end
private
def comment_params
params.require(:comment).permit(:user_id, :body, :rating)
end
end
and the comment.html.erb
<div class="row">
<div class="col-sm-6">
<% if signed_in? %>
<h4>Add a review:</h4>
<%= form_for([#product, #product.comments.build]) do |f| %>
<p>
<%= f.label :body, "Comment" %><br>
<%= f.text_area :body, class: "form-control" %>
</p>
<p>
<%= f.label :rating %><br>
<%= f.text_field :rating, class: "rating form-control" %>
</p>
<p>
<%= f.submit "Submit", class: "btn" %>
</p>
<% end %>
<% end %>
</div>
</div>
Try redirect_to #product instead of redirect_to products_path(#product).
Did you check your routes.rb under config? Try running rake routes in the terminal and you can debug from there.
I'm building a simple blog tool using rails and having trouble with variables displaying from a form. What is most confusing is that the post times are showing correctly, but the title and text aren't coming through.
My new form page looks like:
<h1>New post</h1>
<%= form_for :blog, url: blogs_path do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :body %><br>
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
The controller is currently:
class BlogsController < ApplicationController
def index
end
def new
end
def create
#blog = Blog.new(post_params[:id])
#blog.save
redirect_to #blog
end
def show
#blog = Blog.find(params[:id])
end
private
def post_params
params.require(:blog).permit(:title, :body)
end
end
And the show page is:
<div id="blog">
<h1>
<%= #blog.title %>
</h1>
<p class="date">
Submitted <%= time_ago_in_words(#blog.created_at) %> ago
</p>
<p>
<%= #blog.body %>
</p>
</div>
Any ideas?
Change:
def create
#blog = Blog.new(post_params[:id])
#blog.save
redirect_to #blog
end
to:
def create
#blog = Blog.new(post_params)
#blog.save
redirect_to #blog
end
The reason why it wasn't working is that you were only trying to savepost_params[:id]. You need to pass the whole param as an argument when creating a new blog post Blog.new(post_params)
I have the following controller :
class PostsController < ApplicationController
def index
end
def new
end
def create
#post = Post.new(post_params)
#post.save
redirect_to #post
end
private
def post_params
params.require(:post).permit(:title, :body)
end
end
ANd my model is
class Post < ActiveRecord::Base
end
My new.html.erb page is
<h1> New post </h1>
<%= form_for :post, url:posts_path do |f| %>
<p>
<%= f.label :title %> <br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :body %><br>
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
routes :
Rails.application.routes.draw do
resources :posts
root "posts#index"
end
I keep getting this error :
ArgumentError in PostsController#create
wrong number of arguments (1 for 0)
what did I do wrong here ?