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 ?
Related
im beginner of ruby on rails. i have brand - products list.
Brand,
class Brand < ApplicationRecord
has_many :products, dependent: :destroy
validates :title, presence: true,
length: { minimum: 2 }
end
Product,
class Product < ApplicationRecord
belongs_to :brand
end
products.controller
class ProductsController < ApplicationController
skip_before_action :verify_authenticity_token
def edit
#product = Product.find(params[:id])
end
def new
#product = Product.new
end
def update
#brand = Brand.find(params[:brand_id])
#product = Product.find(params[:id])
#product.update(product_params)
redirect_to brand_path(#brand)
end
def create
#brand = Brand.find(params[:brand_id])
#product = #brand.products.create(product_params)
redirect_to brand_path(#brand)
end
def destroy
#brand = Brand.find(params[:brand_id])
#product = #brand.products.find(params[:id])
#product.destroy
redirect_to brand_path(#brand)
end
def update
#brand = Brand.find(params[:brand_id])
#product = #brand.products.find(params[:id])
#product.destroy
end
helper_method :update
private
def product_params
params.require(:product).permit(:name)
end
end
the new.html.erb,
<h1> Add a new product </h1>
<%= form_with model: #brand, local: true do |form| %>
<p>
<%= form.label :title,"Product name" %><br>
<%= form.text_field :name %>
</p>
<p>
<%= form.label :title,"Select a Brand" %><br>
<%= form.collection_select(:brand, Brand.all, :id, :title) { #brand = Brand.find(params[:brand_id]) } %>
</p>
<p>
<%= form.submit "Save Product", :onclick => "create" %>
</p>
<% end %>
routes.rb
Rails.application.routes.draw do
get 'welcome/index'
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
resources :brands do
resources :products
end
root 'welcome#index'
end
when i cliked the button i get error,
No route matches [POST] "/brands/%23%3CBrand::ActiveRecord_Relation:0x00007f5e30d87490%3E/products/new"
Rails.root: /home/berkay/e-ticaret
SO, how can i save this product?
change that one
<%= form_with model: #brand, local: true do |form| %>
to
<%= form_with(model: #product, url: [#brand, #product]) %>
Also add
#brand = Brand.find(a_brand_id)
inside your new method of ProductsController class. So, rails is going to know which brand is parent of that product.
UPDATE
I've created a dummy project which is going to work as you expected.
products/_form.html.erb partial for product
<%= form_with(model: product, local: true) do |form| %>
<% if product.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(product.errors.count, "error") %> prohibited this product from being saved:</h2>
<ul>
<% product.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :title %>
<%= form.text_field :title %>
</div>
<div class="field">
<%= form.label :title, "Select a Brand" %><br>
<%= form.collection_select(:brand_id, Brand.all, :id, :title, {selected: #brand.id}) %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
routes.rb
Rails.application.routes.draw do
resources :products
resources :brands
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
products_controller.rb
class ProductsController < ApplicationController
# GET /products/new
def new
if params[:brand_id]
#brand = Brand.find(params[:brand_id])
end
#product = Product.new
end
def edit
#brand = #product.brand
end
...
# Never trust parameters from the scary internet, only allow the white list through.
def product_params
params.require(:product).permit(:title, :brand_id)
end
end
I've also added a hotlink to create a product for a given brand
brands/show.html.erb
<p id="notice"><%= notice %></p>
<p>
<strong>Title:</strong>
<%= #brand.title %>
</p>
<%= link_to 'Edit', edit_brand_path(#brand) %> |
<%= link_to 'Back', brands_path %> |
<%= link_to 'Create Products', new_product_path(brand_id: #brand.id) %>
When using nested routes you would have to write
form_with model: [#brand, #product]
it will use the array to compose the path and the last item will be actually edited.
Your new action should best be changed as follows:
def new
#brand = Brand.find(params[:brand_id)
#product = #brand.products.build
end
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)
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 %>.
this error is occuring and i have no idea why, thanks,
undefined method `article_path' for #<#:0x000001029cb960>
edit.html.erb
<h1>Editing <%= #article.name %></h1>
<%= form_for(#article) do |f| %> <-- ????something here?
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
articles model
class MediaController < ApplicationController
def index
#articles = Articles.all
end
def show
#article = Articles.find(params[:id])
end
def edit
#article = Articles.find(params[:id])
end
def update
#article.find(params[:id])
article_params = params.require(:article).permit(:name, :description, :location)
#article.update(article_params)
redirect_to #article
end
end
routes.rb
resources :media
patch "events/:id" => "media#update", as: "update_medium"
Change your routes to
patch "articles/:id" => "media#update", as: "update_medium"
And model name to singular like :
#articles = Article.all
I have two models pages and author, here is the code of model pages:
edit -1
now my models are as follows:
class Page < ActiveRecord::Base
validates :title, :presence => true
belongs_to :author
end
author model:
class Author < ActiveRecord::Base
has_many :pages
end
and my form is as follows:
<%= form_for(#page) do |f| %>
<% if #page.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#page.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #page.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>
<p>
<%= f.label :body %><br />
<%= f.text_area :body %>
</p>
<p>
<%= f.fields_for :author do |fields| %>
<%= f.label :author %><br />
<%= fields.text_field :author %>
<% end %>
</p>
<p>
<%= f.label :email %><br />
<%= f.text_field :email %>
</p>
<p>
<%= f.label :reference %><br />
<%= f.select(:reference,[['google',1],['yahoo',2],['MSN',3],['Ask',4]]) %>
</p>
<%= f.submit "Submit" %>
<% end %>
and controller :
class PagesController < ApplicationController
def index
#total = Page.count
#pages = Page.find(:all)
end
def show
#page = Page.find(params[:id])
end
def new
#page = Page.new
end
def create
#page = Page.new(params[:page])
if #page.save
redirect_to pages_path, :notice => "The data has been saved!"
else
render "new"
end
end
def edit
#page = Page.find(params[:id])
end
def update
#page = Page.find(params[:id])
if #page.update_attributes(params[:page])
redirect_to pages_path, :notice => "Your post has been updated!"
else
render "edit"
end
end
def destroy
#page = Page.find(params[:id])
#page.destroy
redirect_to pages_path, :notice => "Your page has been deleted!"
end
end
Now when i am submitting the form it is giving me this error:
ActiveRecord::AssociationTypeMismatch in PagesController#create
Author(#40328004) expected, got ActiveSupport::HashWithIndifferentAccess(#32291496)
Rails.root: C:/rorapp
Application Trace | Framework Trace | Full Trace
app/controllers/pages_controller.rb:19:in `new'
app/controllers/pages_controller.rb:19:in `create'
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"hzBlXsdUjEDDCLp036R8bJBwep6BdATSvJPNwt0M8Dg=",
"page"=>{"title"=>"",
"body"=>"",
"author"=>{"author"=>""},
"email"=>"",
"reference"=>"1"},
"commit"=>"Submit"}
Show session dump
Show env dump
Response
Headers:
None
and one more problem if I add accepts_nested_attributes_for :author to my Page model, then the field is not displayed at all. I really want to accomplish this.. any help?
Apparently this doesn't work in reverse with the association. I'm sorry for the mistake. You could do the following, but then your pages controller is acting on the author, which isn't really appropriate. You could make an author controller though, and include fields_for :pages, to have the author and the first page created at the same time.
class PagesController < ApplicationController
def new
#author = Author.new
#page = #author.pages.new
end
def create
#author = Author.create(params[:author])
end
end
class Author < ActiveRecord::Base
has_many :pages
accepts_nested_attributes_for :pages
end
class Page < ActiveRecord::Base
belongs_to :author
end
<%= form_for(#author, :url => pages_url) do |f| %>
<%= f.text_field :author %>
<%= f.fields_for :pages do |fields| %>
<%= fields.text_area :body %>
<% end %>
<% end %>