Trying to pass parameters - ruby-on-rails

I'm trying to pass URL params into my Rails app (Ex: /entries/new?name=asdf
Controller:
def new
#entry = Entry.new(params[:name])
end
def create
#entry = Entry.new(params[:name])
if #entry.save
redirect_to #entry, notice: 'Entry was successfully created.'
else
render :new
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_entry
#entry = Entry.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def entry_params
params.require(:entry).permit(:name)
end end
Form field :
<%= hidden_field_tag :name, params[:name] %>
I'm getting the error "When assigning attributes, you must pass a hash as an argument."
Any ideas?

params is a Hash. params[:name] will return a string ('asdf' in your example above). When instantiating Entry you're only passing the string when you should be passing a hash. Assuming that name is an attribute on your Entry model, you'll need to do this
#entry = Entry.new(name: params[:name])

Use rails generate scaffold Entry and take a look to the generated code. What you're trying to do don't have much sense

Related

param is missing or the value is empty: ph - rails

This is a possible duplicate, but I have read and tried nearly all suggestions, but I keep getting the error on the New action view. I am using Rails 5.
I have tried the following:
private
def ph_params
params.require(:ph).permit(:amount)
end
And also tried the following, and the error disappeared, but my values were not saving to database, only shows Nil:
private
def ph_params
params.permit(:amount)
end
My controller:
class PhsController < ApplicationController
def index
end
def new
#ph = Ph.new(ph_params)
end
def create
#ph = Ph.new(ph_params)
respond_to do |format|
if #ph.save
format.html { redirect_to #ph }
else
format.html { render "new" }
end
end
end
def show
#ph = Ph.find(params[:id])
end
private
def ph_params
params.require(:ph).permit(:amount)
end
end
new.html.erb form start
<%= simple_form_for #ph, url: phs_path do |f| %>
Model
class Ph < ApplicationRecord
end
I might be missing something. Your assistance is appreciated, thank you in advance.
Modify your new action to
def new
#ph = Ph.new
end
The reason you're getting the error is because when you hit the route phs/new, no key ph is passed in the params hash to the controller but you're trying to access params[:ph][:amount] which is the return value of ph_params. This is why the error 'param is missing or the value is empty' occurs.
If you want to know what values were passed in the params has for every request, add the following line to your application.html.erb
<%= params.inspect %>
You'll probably find a hash with two keys {"controller" => "phs", "action" => "new"} in the new page.
However, when you try to create a new ph object, you will find a key ph in your params hash.
By the way, I think you don't quite understand strong parameters. I would suggest you to read http://api.rubyonrails.org/classes/ActionController/StrongParameters.html

How does rails populate forms?

Let's say I create a scaffold:
rails g scaffold Cat name:string age:integer
and I add a presence validation on the Cat model's age attribute:
validates :age, presence: true
When I attempt to create a cat via the form, and put in the cat's name but purposely leave out the cat's age the controller bounces me back to the form but that cat's name is still present in the name field!
How is this happening?
I would have thought the
#cat = Cat.new
would replace all of the invalid cat's attributes. Maybe if it were #cat ||= Cat.new I could understand that more.
Also, how can I make this behaviour happen in a more complex rails app? I have a simple forum where topics has_many replies. I create my new replies via a form in my topic show view:
topic#show:
#reply = Reply.new
topic/show.html.erb:
<%= form_for [#toplic, #reply] do |f| %>
<%= f.text_field :name placeholder: 'Create a new name...' %><br>
<%= f.text_area :description, placeholder: 'Create a new description...', rows: 5 %><br>
<%= f.submit 'Create Discussion' %>
<% end %>
While everything works perfectly, when I purposely leave out a reply's name, though I am redirected back to the form and an error flash shows, my form is completely empty. All of the attributes have vanished? Why is this?
The key to understanding how this works is to realize that in the case of a form failure, the controller action is not rerun, but rather the template is rendered using the existing state from the action.
In a typical Rails scaffold, your create action will look like this
def create
#cat = Cat.new(cat_params) # instance variable is initialized with the form values
if #cat.save
redirect_to #cat, notice: 'Success!'
else
# in the case of form failure, we will re-render the 'new' template
# this will NOT rerun the entire 'new' action, thus the #cat variable
# will still maintain the values from the form that we gave it above
render 'new'
# note the difference if we had instead done a redirect_to; this would
# cause the CatsController#new action to be re-run which would reinitialize
# the #cat variable according to the code within the 'new' action
# redirect_to new_cat_url
end
end
For your more complex example, you'll want to follow the same procedure, making sure you just re-render the form and don't redirect to another action (which will cause the state to be lost).
# TopicsController
def show
#topic = Topic.find(params[:id])
#reply = Reply.new
end
# RepliesController
def create
#reply = Reply.new(reply_params) # init the var with the form values
if #reply.save
redirect_to #topic, notice: 'Success!'
else
# this is the key - we need to re-render the template of the previous action
# in this case, it would be the TopicsController#show template
render 'topics/show'
# Remember - if we instead do a redirect_to #topic, then we will lose the form
# values which are currently set in the #reply variable.
end
end
In short, make sure you recognize when you are redirecting to a new action versus just re-rendering a template.
One important GOTCHA to be aware of when re-rendering a template is that you must make sure that all the instance variables which exist for the controller action are available when you render the template.
For example,
# TopicsController
def show
#topic = Topic.find(params[:id])
#reply = Reply.new
#foo = Foo.new
end
# RepliesController
before_action :set_topic
def create
#reply = Reply.new(reply_params)
if #reply.save
# ...
else
# we need to remember to set up a #foo variable here otherwise it will be undefined
# when used within the 'show' template
#foo = Foo.new
render 'topics/show'
end
protected
def set_topic
#topic = Topic.find(params[:topic_id])
end
OK, so, you go go /cat/new. Rails' route for this URL runs the method CatsController#new, which renders the new.html.erb template. You put in your data, then hit submit. The action for this form is to POST to /cats, which runs the CatsController#create method. This method does this following:
#cat = Cat.new(cat_params)
It then tries to save the Cat. If it succeeds, it redirects you to the Cat's URL. If not, it re-renders the new.html.erb template. That's where the name comes from — the CatsController#update method creates its Cat from the values you put into the original form.
For a typical scaffold create action:
# POST /products
# POST /products.json
def create
#product = Product.new(params[:product])
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render json: #product, status: :created, location: #product }
else
format.html { render action: "new" } #will re-submit
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
The magic happens in the render method! which will submit the previous POST request (won't go back to the new action while a redirect will do), this way the submited values are still there. (check this SO question for more details)
That's said, this behavior relies on following the convention, however sometimes you need to give it a hand specially with some inputs (e.g selects, checkboxes, radio) might require extra setup using selected or value options

Edit user input from form_for

Currently i'm using form_for read read a text_field called :comment, after the user submit it goes to the controller as such:
def create
#entry = Entry.new(entry_params)
if #entry.save
redirect_to :back
else
render 'new'
end
end
private
def entry_params
params.require(:entry).permit(:comment)
end
my question is whether I can search inside :comment (string) for a substring "test", when submitting?
Thanks
You can access what was submitted in the comment text field with params[:entry][:comment], so you should be able to compare it to the value you want with params[:entry][:comment].include?("test")

Rails 4: How do I handle a submitted form where nothing was selected?

Sorry if the title is a little confusing. I have a form for an Item with the field name. There's a text field where the user can input a name and submit it. But if the user doesn't type in anything and hits submit, Rails gives me a param not found: item error, and I'm not sure who to get around this.
items_controller.rb
def new
#item = Item.new()
respond_to do |format|
format.html
format.json { render json: #item }
end
end
def create
#item = Item.new(item_params)
respond_to do |format|
if #item.save
format.html { redirect_to items_path }
format.json { render json: #item, status: :created, location: #item }
else
format.html { render action: 'new', :notice => "Input a name." }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
private
def item_params
params.require(:item).permit(:name)
end
app/views/items/new.html.haml
= form_for #item do |f|
= f.label :name
= f.text_field :name
= f.submit "Submit"
The params.require(:item) part is what is causing the error. What the convention for handling the error when params[:item] isn't present?
It's late for an answer but i'll still write it for someone else. As stated in rails guides you need to use fetch instead of require in strong parameters, by using fetch you can provide a default value if nothing is passed as input. Something like:
params.fetch(:resource, {})
Update:
Scaffolded rails4 app:
https://github.com/szines/item_17751377
It works if a user keep name field empty when create a new item...
Looks, it works without problem...
Development.log shows that parameters would be the following if user keep a field empty:
"item"=>{"name"=>""}
There is always something in the hash...
As Mike Li already mentioned in a comment, something wrong... because shouldn't be empty this params[:item]...
You can check if something nil, with .nil? , in this case params[:item].nil? will be true if it is nil. Or you can use .present? as sytycs already wrote.
Previous answer:
If you have situation when :item is empty, you should just use params[:item] without require.
def item_params
params[:item].permit(:name)
end
More information about require in strong_parameters.rb source code:
# Ensures that a parameter is present. If it's present, returns
# the parameter at the given +key+, otherwise raises an
# <tt>ActionController::ParameterMissing</tt> error.
#
# ActionController::Parameters.new(person: { name: 'Francesco' }).require(:person)
# # => {"name"=>"Francesco"}
#
# ActionController::Parameters.new(person: nil).require(:person)
# # => ActionController::ParameterMissing: param not found: person
#
# ActionController::Parameters.new(person: {}).require(:person)
# # => ActionController::ParameterMissing: param not found: person
def require(key)
self[key].presence || raise(ParameterMissing.new(key))
end
I personally have not switched to strong parameters so I'm not sure how one should handle something like:
params.require(:item).permit(:name)
but you can always check for item presence with something like:
if params[:item].present?
…
end

Send parameter to render

I have a form for creating a ticket, which needs an id of a project. This works but not when it comes to validation. If validation won't pass 'render :new' is executed and the project_id doesn't come with it.
I have tried 'redirect_to new_ticket_path(:project_id => params[:ticket][:project_id]) which renders the form again, but the error messages won't show up so it seems that I need to use 'render :new'.
How can I pass the project_id back to the form or reach project_id from the form without passing it?
def new
#ticket = Ticket.new
#id = params[:project_id]
#project = Project.find(#id)
end
def create
#ticket = Ticket.new(params[:ticket].merge(:user_id => current_user.id))
if #ticket.save
redirect_to #ticket
else
render :new <--- will render without the project_id
end
end
That will render just the view for 'new', but will not run the controller action. You'd need to set up your variables for the 'new' view in your 'create' action.
From http://guides.rubyonrails.org/layouts_and_rendering.html#using-render
Using render with :action is a frequent source of confusion for Rails
newcomers. The specified action is used to determine which view to
render, but Rails does not run any of the code for that action in the
controller. Any instance variables that you require in the view must
be set up in the current action before calling render.
The easiest way around this is to change 'new':
def new
#ticket = Ticket.new(:project_id => params[:project_id])
end
and change any references to #project in your 'new' form to #ticket.project. At that point, you shouldn't have to add anything to your 'create' action as long as your form includes a hidden field for the ticket's project id.
The easiest way to get this working (and I would do this anyway) is to nest the task resource under projects. That way you will always have project_id available in params.
# config/routes.rb
resources :projects do
resources :tasks
end
The urls will look like projects/123/tasks/new etc. Take a look at rake routes.
Write project id into a hidden field in your form and you will okay. And don't forget to initialize #id in your create action
def new
#ticket = Ticket.new
#id = params[:project_id]
#project = Project.find(#id)
end
def create
#ticket = Ticket.new(params[:ticket].merge(:user_id => current_user.id))
#id = params[:project_id] # but make sure it is under this key in params
if #ticket.save
redirect_to #ticket
else
render :new <--- will render without the project_id
end
end
and in the form add
<%= hidden_field :project_id, '', value: #id %>
Why don't you use:
flash[:alert] = #ticket.errors.inspect
redirect_to new_ticket_path(:project_id => params[:ticket][:project_id])

Resources