No post parameters sent when a form is submitted - ruby-on-rails

I have a model called AlphaUser. When I submit a form to create a new alpha user, I'm told there wasn't any data in the params[:post]. How can this happen?
My code for the form:
<%= form_for :alpha_user,
url: alpha_users_path,
class: "form",
id: "alphaTest" do |f| %>
<div class="form-group">
<%= f.label :email %>
<%= f.text_field :email,
class: "form-control", placeholder: "grandma#aol.com" %>
<%= f.text_field :producer,
class: "hidden", value: "0" %>
</div>
<%= f.submit "Request Access", class: "btn btn-primary" %>
<% end %>
My controller:
class AlphaUsersController < ApplicationController
def create
render text: params[:post].inspect
end
end
Data is still recieved, just in this format:
{"utf8"=>"✓", "authenticity_token"=>"blahblahblah", "alpha_user"=>{"email"=>"test#test.com", "producer"=>"0"}, "commit"=>"Request Access", "action"=>"create", "controller"=>"alpha_users"}

You need to call params for the :alpha_user... e.g. params[:alpha_user].
If you're using strong_parameters in Rails 4, this should do the trick:
class AlphaUsersController < ApplicationController
def create
#alpha_user = AlphaUser.new(alpha_user_params)
#alpha_user.save
end
private
def alpha_user_params
params.require(:alpha_user).permit(:email, :producer)
end
end
Notice that in your create action you are no longer referencing the params directly, but the alpha_user_params method required by strong_parameters.

Check this answer: Custom name for params hash from Rails form_for
Also there's a reason for this naming convention. Look here through section 7 "Understanding Parameter Naming Conventions".

Related

First argument in form cannot contain nil or be empty - Rails

I got this error with my user registration form in Rails:
ActionView::Template::Error (First argument in form cannot contain nil or be empty)
View:
<%= form_for User.new, url: create_user_path, method: :post do |f| %>
<div class="form-group">
<%= f.label :name, t("settings.account.fullname"), class: "form-label" %>
<%= f.text_field :name, class: "form-control #{form_is_invalid?(User.new, :name)}", placeholder: t("settings.account.fullname"), autofocus: "", required: "" %>
<div class="invalid-feedback d-block"><%=User.new.errors.full_messages_for(:name).first %></div>
</div>
Controller:
def create
#user = User.new(user_params)
#user.provider = #user_domain
end
and so on..
I'm new to ROR. Can any one help me with this please?
Apart from the bizarre error message this is just not how you do forms in Rails.
Since you're passing User.new to the form it will always be bound to a new instance of User. That means that anything the user has entered into the form will blanked out on an invalid form submission. User.new.errors.full_messages_for(:name).first will give a nil error since there are no validation messages on a record that has not been validated.
What you actually want is something like:
# routes.rb
resources :users
class UsersController < ApplicationController
# GET /users/new
def new
#user = User.new
end
# POST /users
def create
#user = User.new(user_params)
#user.provider = #user_domain
# ...
end
# ...
end
<%= form_with(model: #user) do |form| %>
<div class="form-group">
<%= f.label :name, t("settings.account.fullname"), class: "form-label" %>
<%= f.text_field :name, class: "form-control #{form_is_invalid?(User.new, :name)}", placeholder: t("settings.account.fullname"), autofocus: "", required: "" %>
<% if #user.errors.has_key?(:name) %>
<div class="invalid-feedback d-block">
<%= #user.errors.full_messages_for(:name).each do |msg| %>
<p><%= msg %></p>
<% end %>
</div>
<% end %>
<% end %>
If you just follow the Rails conventions you do not need to specify the URL or the method which are derived from the record. This lets you reuse the same form for updating existing records without changing anything in your code.
create_user_path is in itself extremely unidiomatic as Rails doesn't have a separate path for creating records. You create records by sending a POST request to the collection path (/users).

how to get session variable from params in rails (undefined method '*' for nil class

In the first controller, I set my session variables:
def show
#item = Item.find(params[:id])
session[:item_id] = #item.id
session[:amount] = params[:amount]
end
My view sets the amount with a form_tag:
<%= form_tag checkout_transaction_path, method: :get do %>
<%= label_tag :amount %>
<%= text_field :amount, placeholder: "Total bid amount", autofocus: true %>
<%= submit_tag "submit" %>
<% end %>
The parameters that get sent with this form look like this:
Parameters: {"utf8"=>"✓", "amount"=>{"{:placeholder=>\"Total bid amount\", :autofocus=>true}"=>"1111"}, "commit"=>"Confirm offer", "id"=>"1"}
The second controller tries to assign the session variable to an instance variable.
def checkout
#item = session[:item]
#amount = session[:amount]
end
However, only #item is working. I try to multiply #amount * 0.10 but get this error: undefined method '*' for nil:NilClass
What causes that error? The submit params says it's being submitted, but maybe something is up with the way I try to retrieve it? session[:item_id] goes through perfectly.
You have issue here:
Parameters: {"utf8"=>"✓", "amount"=>{"{:placeholder=>\"Total bid amount\", :autofocus=>true}"=>"1111"}, "commit"=>"Confirm offer", "id"=>"sam-lipp-abandonment"}
In your parameters, you send amount parameters but in amount, you send HTML form "amount"=>{"{:placeholder=>\"Total bid amount\", :autofocus=>true}"=>"1111"}, but should send only value what you set in the amount form, and your amount parameters should looks like this example! "amount"=>"1"
So this means that your form doesn't work correctly!
Try please replace your form on this one, and in a controller, you will get amount!
<%= form_for #new_item, url: checkout_transaction_path do |f| %>
<%= f.label :amount %>
<%= f.text_field :amount, placeholder: "Total bid amount", autofocus: true %>
<%= submit_tag "submit" %>
<% end %>
OR the same code for form_tag
<%= form_tag checkout_transaction_path do %>
<%= label_tag :amount %>
<%= text_field_tag :amount, placeholder: "Total bid amount", autofocus: true %>
<%= submit_tag "Submit Post" %>
<% end %>
The problem in your form can be here:
you wrote text_field instead text_field_tag
Also for form_for form, you need to add in the controller in a method with variable what you will use in your form, for example, I'm using variable #new_item where from you call this form, something like this
def new
#new_item = Item.new
end

How to pass parameters from html.erb to a different html.erb

I'm playing with the messenger gem in rails 4.
I have a graph of nodes and I want to be able to bring up a message box (initially in a different page but will make it a partial later) when a node is pressed so that the current user can message that node.
The id for the clicked node is kept in a div called NameID
At the moment all I've got working is a button that opens the new message page and then you can choose a user from a drop down list. I guess I want that drop down list- the recipient- to be prepopulated from the currently clicked node on the index page.
Here is what I have so far:
index.html.erb
<p><a class="btn btn-lg btn-primary" id="BtnMessageNode" href="/messages/new">Start conversation</a></p>
<div id=NameID><<THIS IS POPULATED BY JAVASCRIPT>></div>
messages_controller.rb
class MessagesController < ApplicationController
before_action :authenticate_user!
def new
#chosen_recipient = User.find_by(id: params[:to].to_i) if params[:to]
end
def create
recipients = User.where(id: params['recipients'])
conversation = current_user.send_message(recipients, params[:message][:body], params[:message][:subject]).conversation
flash[:success] = "Message has been sent!"
redirect_to conversation_path(conversation)
end
end
helpers/messages_helper.rb
module MessagesHelper
def recipients_options(chosen_recipient = nil)
s = ''
User.all.each do |user|
s << "<option value='#{user.id}' data-img-src='#{gravatar_image_url(user.email, size: 50)}' #{'selected' if user == chosen_recipient}>#{user.name}</option>"
end
s.html_safe
end
end
messages/new.html.erb
<% page_header "Start Conversation" %>
<%= form_tag messages_path, method: :post do %>
<div class="form-group">
<%= label_tag 'message[subject]', 'Subject' %>
<%= text_field_tag 'message[subject]', nil, class: 'form-control', required: true %>
</div>
<div class="form-group">
<%= label_tag 'message[body]', 'Message' %>
<%= text_area_tag 'message[body]', nil, cols: 3, class: 'form-control', required: true %>
</div>
<div class="form-group">
<%= label_tag 'recipients', 'Choose recipients' %>
<%= select_tag 'recipients', recipients_options(#chosen_recipient), multiple: true, class: 'form-control chosen-it' %>
</div>
<%= submit_tag 'Send', class: 'btn btn-primary' %>
<% end %>
There are basically two ways to pass parameters to GET routes:
A. Named segments
/users/:user_id/message/new
This nested route would be great if you are sending a message to a single user.
B. Query parameters
Rails supports query parameters as well:
/message/new?to=2
Rails automatically adds query parameters to the params hash. So in this case you would do params[:to].
You can use the Rails route helpers so that you don't have to deal with encoding urls yourself:
new_message_path(to: #user.id)
Use query params for optional parameters like filters and sorting or in this case a preset. Don't use them like users?id=5.

Email form data in rails without model

I have a form that I've created to capture simple contact information from a user:
views/whitepapers/index.html.erb
<%= form_tag({action: "download"}, id: "whitepaper-form-#{w.id}") do %>
<%= label_tag 'name' %>
<%= text_field_tag "contact[name]", nil, class: "form-control" %>
<br/>
<%= label_tag 'email' %>
<%= email_field_tag "contact[email]", nil, class: "form-control" %>
<br/>
<%= label_tag 'phone' %>
<%= text_field_tag "contact[phone]", nil, class: "form-control" %>
<%= hidden_field_tag 'id', w.id %>
<%= hidden_field_tag 'whitepaper-name', w.title %>
<%= submit_tag "Download Now", class: "btn btn-success", id: "whitepaper-# {w.id}-submit" %>
<% end %>
Now, Once the user clicks the "Download" button, the file downloads, so I have that part taken care of. Now I'd like to email the form data without saving anything to the DB.
I've created the mailer: mailers/whitepaper_download_mailer.rb
class WhitepaperDownloadMailer < ApplicationMailer
def email_lead(contact)
#contact = contact
mail to: "admin#example.co", subject: "A Whitepaper Download!"
end
end
And I've started working on implementing in the controller, but all the examples I've run across have to do with data including the model. This is what I have so far, but it's not working in my controller:
controllers/whitepapers.rb
def download
#whitepaper = Whitepaper.find(params[:id])
#contact.name = params[:contact_name]
#contact.email = params[:contact_email]
#contact.phone = params[:contact_phone]
#contact.whitepaper_name = params[:whitepaper_name]
file_path = File.join(Rails.root, "public", #whitepaper.whitepaper_url)
send_file file_path
WhitepaperDownloadMailer.email_lead(#contact).deliver_now
end
models/whitepaper.rb
class Whitepaper < ActiveRecord::Base
mount_uploader :whitepaper, WhitepaperUploader
validates :title, presence: true
validates :abstract, presence: true
validates :whitepaper, presence: true
end
Obviously, I know this isn't going to work since I'm passing #contact to the mailer, but pulling form params into a structure (i.e. #contact.name). Should I be passing each of the parameter variables into the mailer:
WhitepaperDownloadMailer.email_lead(#contact.name, #contact.email, #contact.phone).deliver_now
Or is there some other way that I haven't found yet to make this mailer work?
I figured this out with help from #kevinthompson and Openstruct. So, directly from the form, in my controller controllers/whitepapers.rb:
def contact
#whitepaper = Whitepaper.find(params[:contact][:whitepaper_id])
file_path = File.join(Rails.root, "public", #whitepaper.whitepaper_url)
send_file file_path
if request.post?
#contact = OpenStruct.new(params[:contact])
WhitepaperDownloadMailer.email_lead(#contact).deliver_now
end
end
I also ended up changing the form_tag action in the view to coincide:
<%= form_tag({action: "contact"}, id: "whitepaper-form-#{w.id}") do %>

Understanding of Rails 4's strong parameters

I'm totally new to Rails and I'm playing with it. Now I'm trying to understand the strong parameter feature introduced in Rails 4. Below is my code:
class PostsController < ApplicationController
def index
end
def show
end
def create
p = Post.new(create_post_params)
p.save
redirect_to p
end
def new
end
private
def create_post_params
params.require(:post).permit :title, :body
end
end
Beside the controller, I also have a Post model with a title and a body. My question is what is this :post thing in params.require(:post).permit :title, :body? I write it as :post, is it because I'm currently inside the PostsController? Or I'm reading the properties of a Post?
Edit
Based on gdpelican's answer, if my new.html.erb is like this:
<h1>Create a post</h1>
<%= form_for :post, url: posts_path do |f| %>
<div class="form-group">
<%= f.label :title %>
<%= f.text_field :title, class: "form-control" %>
<p class="help-block">Please type the title of the post</>
</div>
<div class="form-group">
<%= f.label :body %>
<%= f.text_area :body, class: "form-control", rows: 5 %>
<p class="help-block">Please type the body of the post</>
</div>
<%= f.submit class: "btn btn-primary" %>
<% end %>
It's the :post part in <%= form_for :post, url: posts_path do |f| %> determines that I should use :post in params.require(:post).permit :title, :body, right?
Your parameters (typically) look like this
{"utf8"=>"✓", "authenticity_token"=>"...", "post"=>{"title"=>"My title", "body" =>"Body of my Post"}}
When you require a specific key from the parameters (for example post) Rails will throw an error if the hash it was passed doesn't have "post"=>{....}, then once it passes that check it permits the allowed keys and returns only the parameters nested under "post" hash allowed. To copy the api docs examples
params = ActionController::Parameters.new({
person: {
name: 'Francesco',
age: 22,
role: 'admin'
}
})
params.require(:person).permit(:name, :age)
=>{"name"=>"Francesco", "age"=>22}
So after your strong params check, the return is a hash of :post parameters that you have allowed.
EDIT: To answer your second question.
That is one way of thinking about it. Your form syntax (form_for :post) is creating the post hash with the attributes nested inside, and sending it as part of the overall parameters hash. And your params.require(:post) is taking the entire params, and finding only the hash key it wants (post) and then permitting the keys that are inside the post hash.
It is the name of the JSON wrapper of your form values.
The form will typically wrap the form parameters like so:
{
post: {
title: "Title",
body: "Body",
}
}
When using something like form_for #post
In essence, params.require(:post).permit(:title, :body) is saying two things:
my parameters must have a :post attribute
the :post attribute may only have a title and a body parameters, and nothing else.
UPDATE
The parameters in form_for are what affect how your parameters are wrapped.
Generally, the name of the controller matches the name of the form parameters, so in most instances it's a safe assumption that a 'BooksController' will accept form parameters in a 'book' field.

Resources