When i try to create an entry in my application i get
ActionController::ParameterMissing in TodosController#create
param is missing or the value is empty: activity
Expected Source:
def todo_params
params.require(:activity).permit(:name, :due)
end
Here is my request:
{"utf8"=>"✓",
"authenticity_token"=>"mR11T50dN8tm/q+S0fNd+mYYZBR6Xq4it4ujtEOmt/7RmA4TjzTKD//XmFU+UumpbmKcaj9DtG6noHOD2pwk2w==",
"todo"=>{"name"=>"Ezekiel",
"activity"=>"test....an 8th time"},
"commit"=>"Create Todo"}
I am not sure why this is not working as the activity parameter is clearly passed through as it is in the request
Here is the controller:
def create
#todo = Todo.create(todo_params)
end
def todo_params
params.require(:activity).permit(:name, :due)
end
And finally my View:
<div class="reveal" id="ezekielTask" data-reveal>
<%= simple_form_for #todo do |f| %>
<%= f.input :name, :as => :hidden, :input_html => {:value => "Ezekiel"} %>
<%= f.input :activity %>
<%= f.button :submit %>
<% end %>
</div>
This part of my rails application is a todo list, it displays fine, i can add entries through the console, this way just will not work and i have no idea why. it is passing the data correctly just not accepting it.
Controller
def create
#todo = Todo.create(todo_params)
respond_to do |format|
if #todo.save
format.html { redirect_to location_path, notice: 'Todo was successfully created.' }
else
format.html { render :new }
}
end
end
end
Params
def todo_params
params.require(:todo).permit(:name, :activity)
end
You need to change the strong params method to require todo and then accept the :name and :activity params
def todo_params
params.require(:todo).permit(:name, :activity)
end
The reason for that is
{"utf8"=>"✓",
"authenticity_token"=>"mR11T50dN8tm/q+S0fNd+mYYZBR6Xq4it4ujtEOmt/7RmA4TjzTKD//XmFU+UumpbmKcaj9DtG6noHOD2pwk2w==",
"todo"=>{"name"=>"Ezekiel",
"activity"=>"test....an 8th time"},
"commit"=>"Create Todo"}
If you see in the params you are receiving name and activity inside todo
In the require parameter normaly we use the name of the model (todo) and inside permit we use the attributes of that model (:name, :activity)
def todo_params
params.require(:todo).permit(:name, :activity)
end
Related
I know there is so much docs regarding params.require() and I have indeed tried every possible ways to debug the error but its unavoidable -whatever I put in require, it still gives the same error!
Here is the error,
ActionController::ParameterMissing in UserCrudController#update
Request
Parameters:
{"utf8"=>"✓",
"_method"=>"patch",
"authenticity_token"=>"QknxMRZg8aFEkOatw9uxulLUSiEUXgBFQ4iFbbJHIfgvGCtTq2oI3FI7W8eq5Eqeo3Z3dEPWK2IK2XH96f4faQ==",
"user_crud"=>{"name"=>"Chow", "email"=>"ac#gmail.com"},
"commit"=>"Update User",
"id"=>"4"}
And my Controller section:
class UserCrudController < ApplicationController
def update
# Find a new object using form parameters
#users = UserCrud.find(params[:id])
# Update the object
if #users.update_attributes(users_params)
# If save succeeds, redirect to the show action
flash[:notice] = "UserCrud updated successfully."
redirect_to(user_crud_path(#users))
else
# If save fails, redisplay the form so user can fix problems
render('edit')
end
end
def edit
#users=UserCrud.find(params[:id])
end
def users_params
params.require(:name).permit(:name, :email,:created_at,:updated_at)
end
I am using the model as:
class UserCrud < ApplicationRecord
validates_presence_of :name
validates_presence_of :email
end
Now the View is (edit.html.erb):
<% #page_title = "Update User" %>
<%= link_to("<< Back to List", user_crud_path, :class => 'back-link') %>
<div class="users edit">
<h2>Update User</h2>
<%= form_for(#users) do |f| %>
<%= render(:partial => 'form', :locals => {:f => f}) %>
<div class="form-buttons">
<%= f.submit("Update User") %>
</div>
<% end %>
</div>
Just make following changes in your controller,
def user_params
params.require(:user_crud).permit(:name, :email)
end
As your params contains form inputs under user_crud key.
def user_params
params.require(:user_crud).permit(:name, :email,:created_at,:updated_at)
end
You have to change this code:
def users_params
params.require(:name).permit(
:name, :email,:created_at,:updated_at
)
end
to
private
def user_params
params.require(:user_crud).permit(:name, :email)
end
in your controller.
Just to explain, when setting your "resource_params", requiring a param will search for the root of your json. For example:
def resource_params
params.require(:foo).permit(:bar)
end
Your JSON should looks like this:
{
"foo": {
"bar": 123
}
}
I have an order form where my users are suposed to validate the conditions of sales to proceed to payment.
If the user hasn't checked the box, I want him to be warned to do so..
I just don't manage to do that...
Update (add the shopping cart)
the order is initialzed in a shooping cart:
class ShoppingCart
delegate :sub_total, to: :order
def initialize(token:)
#token = token
end
def order
#order ||= Order.find_or_initialize_by(token: #token, status: 0) do |order|
order.sub_total = 0
end
end
end
the form in orders/new.html.erb
<%= simple_form_for #order, url: clients_checkout_path do |f| %>
<div class="<%= 'error_message' if #order.errors.full_messages.any? %> ">
<% if #order.errors.any? %>
<% #order.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
<% end %>
</div>
<%= f.hidden_field :user_id %>
<%= f.input :cgos_accepted, as: :boolean, checked_value: true, unchecked_value: false %>
<%= f.submit, class: "btn btn-main btn-block" %>
<% end %>
here is the controller:
class Clients::OrdersController < Clients::ApplicationController
def index
#orders = Order.all
#orders = #orders.filter_by_status(params[:status]) if params[:status]
end
def show
#order = Order.find(params[:id])
end
def new
#order = current_cart.order
#billing_address = BillingAddress.new
end
def create
#order = current_cart.order
#order.update_sub_total!
#order.update_total!
if #order.update_attributes!(order_params.merge(user_id: current_user.id))
redirect_to new_clients_order_payment_path(#order)
end
end
private
def order_params
params.require(:order).permit(:status, :user_id, :token , :sub_total, :cgos_accepted)
end
end
in my order model I added a validation:
class Order < ApplicationRecord
validate :accept_cgos, on: :update
#[...]
private
def accept_cgos
if self.cgos_accepted == false
errors.add(:base, :must_accept_cgos)
end
end
end
my yml file is:
en:
activerecord:
errors:
models:
order:
attributes:
base:
must_accept_cgos: Please accept the general condition of sales
I was expecting the warning message to be displayed in the div but it is opening Better Error and says:
ActiveRecord::RecordInvalid at /clients/cart/checkout
Validation failed: Please accept the general condition of sales
So it's kinda working but why isn't it displaying in my error div?
update_attributes!
You are using the bang-version of update_attributes, update_attributes!. Just like save! and create! it will throw an exception when saving is unsuccessful.
If you remove the exclamation mark in that method call, update_attributes will return false when being unable to save, instead.
Rendering the error
The other part that is missing is rendering the new template in case of a validation error. If update_attributes returns true, a redirect will take place, but if it returns false, rails will attempt to render create.html.erb by default. But the new template can be also used in this case but rails has to be told to do so.
Code changes
The changed implementation might then look like this.
if #order.update_attributes(order_params.merge(user_id: current_user.id)) # no bang
redirect_to new_clients_order_payment_path(#order)
else
#billing_address = BillingAddress.new # because the #new template requires it.
render :new
end
why isn't it displaying in my error div?
Because of your create action, you're doing the redirect_to, the redirect_to flush the order instance and all your errors from object is vanished, try to add render :new instead.
# for example
def create
if #order.updated
redirect_to path
else
render :new
end
end
I'm a newbie on rails. My rails version is 4.2.6, simple_form_for version is 3.2.1. I want to redirect to the new page after I validated the params is false. And I get the error message.
undefined method `model_name' for nil:NilClass <%= simple_form_for
[:account, #station] do |f| %>
...
let me show you. This is my routes.rb
namespace :account do
resources :stations, expect: [:index]
end
stations_controller.rb
def new
#lines = Line.where(line_status: 1)
#station = Station.new
end
def create
unless check_post_params post_params
flash[:notice] = "miss params"
render action: :new # not work
# render :new # not work
# render 'new' # not work
# it work for me, but can I use render?
#redirect_to '/account/stations/new'
else
#station = Station.new(post_params)
if #station.save
redirect_to '/account/lines'
else
flash[:notice] = 'failed'
redirect_to 'account/stations/new'
end
end
end
private
def post_params
params.require(:station).permit(...)
end
def check_post_params(post_params)
if ...
return false
else
return true
end
end
_form.html.erb
<%= simple_form_for [:account, #station] do |f| %>
<div class="form-group">
<%= f.label :line_id, t('line.line_name') %>
<%= f.input_field :line_id,
... %>
<% end %>
The original I open the URL is http://localhost:3000/acoount/stations/new. After I click the submit, and I want to render :new, it will redirect to original URL, but I found the URL become http://localhost:3000/account/stations. The URL's /new is disappear. I have guessed it's about my routes.rb config.
And I tried to use rake routes to check my routes.
$ rake routes
...
POST /account/stations(.:format) account/stations#create {:expect=>:index]}
new_account_station GET /account/stations/new(.:format) account/stations#new {:expect=>[:index]}
...
I tried to use render account_stations_new_path and render new_account_station_path, but still not work for me. Thanks your help.
Edit
I know how to modify my code. I should validate my params on my model. And then I should use redirect_to not use render. I will update my code later.
Edit 2
I modified my model.
class Station < ActiveRecord::Base
belongs_to :line
has_many :spot_stations
validates :name, presence: true, uniqueness: { case_sensitive: false }
validates :line_id, presence: true
validates ....
end
And I modified my controller.
def new
# Because this #lines did't exist when I render 'new' on the create method. So I deleted it. And I create a method on the helper.
# #lines = Line.where(line_status: 1)
#station = Station.new
end
def create
#station = Station.new(post_params)
if #station.save
redirect_to '/account/lines'
else
flash[:notice] = 'failed'
render 'new'
end
end
I add a method for getting lines data
module Account::StationsHelper
def get_lines
#lines = Line.where(line_status: 1)
end
end
I will use it on my _form.html.erb
<%= simple_form_for [:account, #station] do |f| %>
<div class="form-group">
<%= f.label :line_id, t('line.line_name') %>
<%= f.input_field :line_id,
collection: get_lines,
label_method: :line_name,
input_html: { class: 'form-control' },
value_method: :id,
prompt: t('common.please_select') %>
</div>
...
<% end %>
This work great for me. Thanks your help.
try this:
if #station.save
redirect_to account_stations
else
flash[:notice] = 'failed'
render 'new'
end
as argument for render method you must pass action name, not url.
I have a Post and a MaterielLink models.
A post has_many materiel_links, and accepts_nested_attributes_for :materiel_links
I use the gem cocoon to create a nested form: on the post form, I want to be able to add links that will be created on submit of the form.
post/new.html.erb:
<%= simple_form_for #post, :html => { :id => "post_form", "data-post-id" => #post.id } do |f| %>
<%= f.simple_fields_for :materiel_links do |materiel_link| %>
<%= render 'materiel_link_fields', f: materiel_link %>
<% end %>
<%= link_to_add_association 'Ajouter', f, :materiel_links%>
<% end %>
_materiel_link_fields.html.erb:
<%= f.fields_for :materiel_links do |materiel_link| %>
<%= materiel_link.text_field :name %>
<%= materiel_link.text_field :link %>
<% end %>
In my post controller:
def update
#materiel_links = #post.materiel_links.build(post_params[:materiel_links_attributes]
if #post.update!(post_params)
session[:current_draft_post_id] = nil
redirect_to post_path(#post)
else
render :new
end
end
I am here in the update action since, for reasons specific to my rails app, the post is created when the posts/new page is rendered (It is created empty, and the user just updates it instead of actually creating it). So the post already exists, but not the materiel_links that I have to create in the update action.
And the params:
def post_params
params.require(:post).permit(:title, materiel_links_attributes: [:name,:link] )
end
I added a raise in the update action, and what is stange is that I can find the link/name for each materiel_link I've added when I type params but with a number before each couple:
>> params
{"utf8"=>"✓", "_method"=>"patch", "authenticity_token"=>"wqzWfaAcwrOOdxViYBO5HaV2bwsNsf5HsvDFEbBYapkOMAPXOJR7oT4zQHbc/hTW8T9a+iH5NRl1WUApxrIjkA==", "post"=>{"title"=>"my title", "materiel_links_attributes"=>{"1459431927732"=>{"materiel_links"=>{"name"=>"mon Lien 1", "link"=>"htttp1"}}, "1459431933881"=>{"materiel_links"=>{"name"=>" Mon lien 2", "link"=>"htttp2"}}}}, "controller"=>"posts", "action"=>"update", "id"=>"1250"}
But nothing in the materiel_links hashes when I type post_params:
>> post_params
=> {"title"=>"my title","materiel_links_attributes"=>{"1459431927732"=>{}, "1459431933881"=>{}}}
The instances of MaterielLink are created, but they are empty: they don't save the link/name.
Where did I go wrong ?
My guess is that because in your update action you used .build before .update, it somehow conflicted with .update because the materiel_links values are passed there once again. You do not need to build in update action anymore; but only in edit action, because the materiel_links will be automatically created/updated when .update(post_params) is called, as post_params already include materiel_links values. Try
def update
if #post.update!(post_params)
#materiel_links = #post.materiel_links
session[:current_draft_post_id] = nil
redirect_to post_path(#post)
else
render :new
end
end
You'd also need whitelist the ID of materiel_link in strong params, so that these materiel_links in the form can be updated (ID not needed to be whitelisted if just create, and no update). You might also want to allow destroy. Update into the following:
def post_params
params.require(:post).permit(:title, materiel_links_attributes: [:id, :name, :link, :_destroy] )
end
# post.rb
accepts_nested_attributes_for :materiel_links, allow_destroy: true
followed a tutorial to help me create instances within a controller. In other words transactions are created on the envelope controller. Like comments on a blog post.
Everything is working perfectly, but I don't know how to edit a transaction now or destroy one. All I need is to find how to edit an existing thing. Let me show you what I have so far:
in views/envelopes/edit (the form code was copied from where you can create new transactions)
<% #envelope.transactions.each do |transaction|%>
<%= form_for [#envelope, #envelope.transactions.build] do |f| %> <!--??? NEED EDIT INSTEAD OF BUILD ???-->
<%= f.text_field :name, "value" => transaction.name %>
<%= f.text_field :cash, "value" => transaction.cash %>
<%= f.submit "Submit" %>
<% end %>
<%= link_to "Remove", root_path %> <!--??? WANT TO REMOVE TRANSACTION ???-->
<% end %>
in routes.rb
resources :envelopes do
resources :transactions
end
in transaction controller
class TransactionsController < ApplicationController
def create
#envelope = Envelope.find(params[:envelope_id])
#transaction = #envelope.transactions.build(transaction_params)#(params[:transaction])
#transaction.save
#envelope.update_attributes :cash => #envelope.cash - #transaction.cash
redirect_to edit_envelope_path(#envelope)
end
def destroy
# ???
end
def update
# ???
end
def transaction_params
params.require(:transaction).permit(:cash, :name, :envelope_id)
end
end
def update
#transaction = #envelope.transactions.find(params[:id])
if #transaction.update(transaction_params)
redirect to #envelope, notice: 'Transaction was successfully updated'
else
redirect_to #envelope, notice: 'Transaction was not updated'
end
end
def destroy
#transaction.destroy
redirect_to #envelope, notice: 'Text here'
end