rails 4 Unpermitted parameters: post_detail - ruby-on-rails

I am getting following error in console
Unpermitted parameters: post_detail
Unpermitted parameters: post_detail
My post model has
has_many :post_details
accepts_nested_attributes_for :post_details
and my post_detial model has
belongs_to :post
has_attached_file :upload
post.rb and post_detail.rb is my model files
posts_controller is controller
Here is my form
Here is my posts_controller.rb
def create
#post = Post.new(post_params)
#post.build.post_detail
end
private
def post_params
params.require(:post).permit(:title,:post_details => [:upload_file_name,:upload_file_size,:upload_file_content])
end
Edit 1
<%= form_for #post,html: {multipart: true} do |f| %>
<%= f.text_field :title,placeholder: 'title' %>
<%= f.fields_for :post_detail do |uploads| %>
<%= uploads.file_field :upload %>
<% end %>
<%= f.submit 'submit' %>
<% end %>
My post controller
def new
#post = Post.new
#post.post_details.build
end
def create
#post = Post.new(post_params)
if #post.save
#some flash
end
end
private
def post_params
params.require(:post).permit(:title,:post_details_attributes => [:id, :upload_file_name,:upload_file_size,:upload_file_content,:_destroy])
end
Still unpermitted parameters: post_details occurs

You should build the post_details in the new action, and then save the post with all the params (including the post_details_attributes) in the create action.
def new
#post = Post.new
#post.post_details.build
end
def create
#post = Post.new(post_params)
#post.save
end
private
def post_params
params.require(:post).permit(:title,:post_details_attributes => [:id, :upload_file_name,:upload_file_size,:upload_file_content, :_destroy])
end

Related

How to implement Update and destroy methods with a has many through association? Rails 5

Hi I'm having trouble by making the update and destroy method in my posts_controller, I'm able to create new Posts but I'm not able to update and I want to know how to destroy the model while destroying all the associations with the other model it.
My models:
Post Model
class Post < ApplicationRecord
has_many :comments, dependent: :destroy
has_many :has_categories
has_many :categories, through: :has_categories
validates :title, presence: true,
length: { minimum: 5 }
after_create :save_categories
def categories=(value)
#categories = value
end
private
def save_categories
#categories.each do |category_id|
HasCategory.create(category_id: category_id, post_id: self.id)
end
end
end
Has_Category model
class HasCategory < ApplicationRecord
belongs_to :post
belongs_to :category
end
Category Model
class Category < ApplicationRecord
validates :name, presence: true
has_many :has_categories
has_many :posts, through: :has_categories
end
So in my partial form for the new and the edit actions is like this
<%= form_with model: #post, local: true do |form| %>
<!--Inputs before the categories-->
<div>
<label>Categories</label>
<% #categories.each do |category| %>
<div>
<%= check_box_tag "categories[]", category.id %> <%= category.name %>
</div>
<% end %>
</div>
<div>
<%= form.submit %>
</div>
<% end %>
My posts_controller create and update method
def create
#post = Post.new(post_params)
#post.categories = params[:categories]
if #post.save
redirect_to #post
else
render :new
end
end
def update
#post = Post.find(params[:id])
#post.categories = params[:categories]
if #post.update(post_params)
redirect_to #post
else
render :edit
end
end
My create action is working but the update action is just updating the inputs before the check_box_tag.
I know that the save_categories method on my Post model is the one who is taking the array I'm receiving from the form and creating the HasCategory association, How should I make the update action or even the destroy action given the situation that Is a many to many association?
The line has_many :categories, through: :has_categories gives you category_ids for post. So you can change your form:
<%= form_with model: #post, local: true do |form| %>
<!--Inputs before the categories-->
<div>
<label>Categories</label>
<%= f.collection_check_boxes(:category_ids, #categories, :id, :name)
</div>
<div>
<%= form.submit %>
</div>
<% end %>
and controller:
def create
# you need it here for correct rerendering `new` on validation error
#categories = Category.all # or maybe you have here more complicated query
#post = Post.new(post_params)
if #post.save
redirect_to #post
else
render :new
end
end
def update
# you need it here for correct rerendering `edit` on validation error
#categories = Category.all # or maybe you have here more complicated query
#post = Post.find(params[:id])
if #post.update(post_params)
redirect_to #post
else
render :edit
end
end
private
def post_params
params.require(:post).permit(:name, :some_other_post_params, category_ids: [])
end
You need to remove callback and categories=(value) method from the Post model. And define #categories in the new and edit actions. If it equals Category.all you can just put it to the form: f.collection_check_boxes(:category_ids, Category.all, :id, :name), without defining #variable

action create couldn't be found for PostsController

I'm following a rails tutorial and need some help to proceed further. Problem is, once I fill out the form which has a title,body fields and hit submit, it has to redirect to the show.html.erb page instead it throws an error.
Error: The action 'create' could not be found for PostsController
routes.rb
Rails.application.routes.draw do
get "/pages/about" => "pages#about"
get "/pages/contact" => "pages#contact"
get "/posts" => "posts#index"
post "/posts" => "posts#create"
get "/posts/show" => "posts#show", as: :show
get "/posts/new" => "posts#new"
end
posts_controller_tests.rb
require 'test_helper'
class PostsControllerTest < ActionController::TestCase
def index
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.save
redirect_to show_path
end
def show
end
private
def post_params
params.require(:post).permit(:title, :body)
end
end
new.html.erb
<h1>Create a new blog post</h1>
<div class="form">
<%= form_for Post.new do |f| %>
<%= f.label :title %>: <br>
<%= f.text_field :title %> <br> <br>
<%= f.label :body %>: <br>
<%= f.text_area :body %> <br> <br>
<%= f.submit %>
<% end %>
</div>
Any help on this would be appreciated.
Note: You are using posts_controller_tests.rb not posts_controller.rb. You are putting your controller code in test controller.
Try to move the code in app/controllers/posts_controller.rb:
class PostsController < ApplicationController
def index
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.save
redirect_to show_path
end
def show
end
private
def post_params
params.require(:post).permit(:title, :body)
end
end
Your create action always redirects you to the show action. It doesn't matter if your model was saved or not.
You have to check if the model was saved or not:
def create
#post = Post.new(post_params)
if #post.save
flash[:success] = 'Successfully saved'
redirect_to #post
else
render 'new'
end
end
If it wasn't saved, it renders the new action again.
Change your routes.rb to this:
Rails.application.routes.draw do
get "/pages/about" => "pages#about"
get "/pages/contact" => "pages#contact"
resources :posts
end
Moreover you should inherit your controller from ActionController::Base
so change first line of your controller to
class PostsController < ActionController::Base
and move the controller to app/controllers/posts_controller.rb

How to use accepts_nested_attributes_for with rails?

I have read these documents:
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-fields_for
http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html
My source:
Model
app/models/product.rb
class Product < ActiveRecord::Base
has_many :product_items, foreign_key: :product_id, :dependent => :destroy
accepts_nested_attributes_for :product_items
end
app/models/product_item.rb
class ProductItem < ActiveRecord::Base
belongs_to :product
end
Controller
app/controllers/products_controller.rb
class ProductController < ApplicationController
def new
#product = Product.new
end
def create
#product = Product.new(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to root_path }
else
format.html { render :new }
end
end
end
private
def product_params
params.require(:product).permit(:name, product_items_attributes: [ :description ])
end
end
View
app/views/products/_form.html.erb
<%= form_for(product, url: path) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.fields_for :product_items do |item_form| %>
<%= item_form.label :description %>
<%= item_form.text_field :description %>
<% end %>
<%= f.submit 'Submit' %>
<% end %>
I can save the product data to the database, but it can't save product_items.
Edit
Add my post data after submit my form:
utf8:✓
authenticity_token:c5sdmoyLoN01Fxa55q6ahTQripx0GZvWU/d27C]asfdawofX9gw==
product[name]:apple
product[product_items][description]:good
commit:Submit
Edit 2
Add rails log:
Started POST "/products" for 10.0.2.2 at 2015-09-15 13:00:57 +0900
Processing by ProductController#create as HTML
I, [2015-09-15T13:00:58.039924 #28053] INFO -- : Parameters: {"utf8"=>"✓", "authenticity_token"=>"bilBzgOLc2/ZRUFhJORn+CJvCHkVJSsHQTg1V/roifoHxi9IRA==", "product"=>{"name"=>"apple", "product_items"=>{"description"=>"good"}}, "commit"=>"Submit"}
Your new method should like below in order to save product_items
def new
#product = Product.new
#product.product_items.build
end
You should also change your product_params like below for the update to work correctly in future.
def product_params
params.require(:product).permit(:name, product_items_attributes: [ :id, :description ])
end
Update your controller action product_params
def product_params
params.require(:product).permit(:name, product_items_attributes: [:id, :description, :_destroy ])
end
Either you can use nested_form gem which provide you complete demo and function control. Here is link https://github.com/ryanb/nested_form

Wrong number of arguments (1 for 0) error when calling markdown method

All,
I just created markdown_title and markdown_body methods. When I go to the show view page for my Post model I am getting the error: Wrong number of arguments.
I believe my markdown_title method(also for markdown_body) might be constructed incorrectly below in the post.rb file. Is this the culprit?:
class Post < ActiveRecord::Base
has_many :comments
has_one :summary
belongs_to :user
belongs_to :topic
#has_one :summary
default_scope {order('created_at DESC')}
validates :title, length: {minimum: 5}, presence: true
validates :body, length: {minimum: 20}, presence: true
validates :topic, presence: true
validates :user, presence: true
def markdown_title
(render_as_markdown).render(self.title).html_safe
end
def markdown_body
(render_as_markdown).render(self.body).html_safe
end
private
def render_as_markdown
renderer = Redcarpet::Render::HTML.new
extensions = {fenced_code_blocks: true}
redcarpet = Redcarpet::Markdown.new(renderer, extensions)
#return redcarpet
end
end
Here is my code for my show.html.erb file where the error is appearing while calling my markdown_title method:
<h1><%= #post.markdown_title #post.title %></h1>
<div class="row">
<div class="col-md-8">
<p><%= #post.body %></p>
</div>
<div class="col-md-4">
<% if policy(#post).edit? %>
<%= link_to "Edit", edit_topic_post_path(#topic, #post), class: 'btn btn-success' %>
<% end %>
</div>
</div>
<% if #post.summary.present? %>
<h1>Post Summary</h1>
<p><%= #post.summary.body %></p>
<% else %>
<%= form_for [#topic, #post, #post.build_summary] do |f| %>
<%= f.text_field :body %>
<%= f.submit %>
<% end %>
<% end %>
This is the Post controller:
class PostsController < ApplicationController
#def index #for the index page
##posts = Post.all
#authorize #posts
#end
def show
#post = Post.find(params[:id])
#topic = Topic.find(params[:topic_id])
end
def new
#topic = Topic.find(params[:topic_id])
#post = Post.new
authorize #post #authorize() will check the policy on new post resources
# if user is present it wll let it render if no user present itll give exception
end
def create
##post = Post.new(params.require(:post).permit(:title, :body))
#require and permit make sure only certain keys are passed to Post.new
#topic = Topic.find(params[:topic_id])
##post = current_user.posts.build(params.require(:post).permit(:title, :body))
#post = current_user.posts.build(post_params)
#post.topic = #topic
authorize #post #authorize() will check if user is logged in if not itll give an exception
if #post.save
flash[:notice] = "Your new post was created and saved."
redirect_to [#topic, #post] #takes you to the new post you created
else
flash[:error] = "There was an error saving the post. Please try again."
render :new # it grabs the new.html.erb file and pastes it in the view
end
end
def edit
#topic = Topic.find(params[:topic_id])
#post = Post.find(params[:id])
authorize #post
end
def update
#topic = Topic.find(params[:topic_id])
#post = Post.find(params[:id])
##post_check = current_user.posts.build(post_params)
authorize #post
if #post.update_attributes(post_params)
flash[:notice] = "Post was updated and captured your new update."
redirect_to [#topic, #post]
else
flash[:error] = "There was an error saving the post. Please try again."
render :new
end
end
private
def post_params
params.require(:post).permit(:title, :body)
end
end
Here is the error I get on my view:
You're calling your markdown_title method with a parameter, in this case, #post.title.
<h1><%= #post.markdown_title #post.title %></h1>
In the definition of your Post class, the markdown_title method doesn't take any parameters.
def markdown_title
(render_as_markdown).render(self.title).html_safe
end
That's why you're seeing the Wrong number of arguments (1 for 0) error.
Since you're already referencing self.title in the markdown_title method, there's no reason to pass #post.title to it. Just remove #post.title from where you're calling markdown_title, and you should be good to go.

ActiveModel::ForbiddenAttributesError in PostsController#create

I've started learning Ruby on Rails.
Iam getting below error: ActiveModel::ForbiddenAttributesError in PostsController#create
Here is the code:
posts_controller.rb
class PostsController < ApplicationController
def index
#posts = Post.all
end
def show
#post = Post.find params[:id]
end
def new
#post = Post.new
end
def create
#post = Post.create(params[:post]) // Its showing me error here
if #post.save
redirect_to posts_path notice: "Your Post was saved"
else
render "new"
end
end
end
new.html.erb
<h1> Add a New Post </h1>
<%= form_for #post do |f| %>
<p>
<%= f.label :title %><b/>
<%= f.text_field :title %><b/>
</p>
<p>
<%= f.label :content %><b/>
<%= f.text_area :content %><b/>
</p>
<%= f.submit "Add a New Post" %>
<% end %>
post.rb
class Post < ActiveRecord::Base
validates_presence_of :title, :content
end
Please tell me what went wrong. BTW, iam using Rails4
In rails4 there is strong parameters so you can't do this:
#post = Post.create(params[:post])
You need
#post = Post.create(post_params)
Where post_params is a method in your controller:
private
def post_params
params.require(:post).permit!
end
permit! will permit anything. You can limit it though to what you want to allow for example params.require(:post).permit(:title, :content)
You have to use strong params for rails 4 to solve this problem.
Docs: http://edgeguides.rubyonrails.org/action_controller_overview.html#strong-parameters
def post_params
params.require(:post).permit(:title, :content)
end
and in create action use: Post.create(post_params)
You have to use strong params always when you create or update a record.

Resources