Is there a way to write a HTML form in rails? - ruby-on-rails

I'm new to RoR and I've stumbled upon a problem. I'm trying to approve or deny a rent, and have been successful in doing so using the HTML form.
<form action="<%= approve_rental_url(rental) %>" method="post">
<input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>">
<input type="submit" value="Approve">
</form>
This code works without a problem and I know that it isn't the rails way of doing it. I've tried to write it in the rails way and have encountered a problem which says No route matches [POST] "/cats/2".
#Ruby code
<%= form_for approve_rental_url(rental) do |f| %>
<%= f.submit "Approve" %>
<% end %>
Here is the rails routes
Prefix Verb URI Pattern Controller#Action
approve_rental POST /rentals/:id/approve(.:format) rentals#approve
deny_rental POST /rentals/:id/deny(.:format) rentals#deny
rentals POST /rentals(.:format) rentals#create
new_rental GET /rentals/new(.:format) rentals#new
cats GET /cats(.:format) cats#index
POST /cats(.:format) cats#create
new_cat GET /cats/new(.:format) cats#new
edit_cat GET /cats/:id/edit(.:format) cats#edit
cat GET /cats/:id(.:format) cats#show
PATCH /cats/:id(.:format) cats#update
PUT /cats/:id(.:format) cats#update
root GET / cats#index

When you use form_for, you have to pass record as argument like this:
<%= form_for :person do |f| %>
First name: <%= f.text_field :first_name %><br />
Last name : <%= f.text_field :last_name %><br />
Biography : <%= f.text_area :biography %><br />
Admin? : <%= f.check_box :admin %><br />
<%= f.submit %>
<% end %>
If you need to pass URL, you need to use form_tag instead of form_for:
form_tag('/posts/1', method: :put)
But these helpers are softly deprecated. Now there is form_with helper.
You can pass to it URL or record
form_with(model: nil, scope: nil, url: nil, format: nil, **options)

Actually, since this is such a common problem, in rails you can just write
link_to 'Approve', approve_rental_url(rental), class: 'btn btn-success', method: :post
or use the button_to helper
button_to 'Approve', approve_rental_url(rental), class: 'btn btn-success'
(which will POST by default)
and both will automatically inline a form to perform the POST.

Related

Undefined method when trying to pass through id

I'm trying to pass a project ID from its show page to an employee_projects form where I can display the projects name. The error I'm getting is
undefined local variable or method `project_id' for #<EmployeeProjectsController:0xb8bdd58>.
employee_project controller:
# GET /employee_projects/new
def new
puts params[project_id]
#project = Project.find(params[:project_id])
session[:project_id] = #project.id
#employee_project = EmployeeProject.new
end
employee_projects form
Assign worker for this project <%= project.projectName%><br>
<div class="field">
<%= f.label :employee_id %><br>
<%= f.collection_select :employee_id, Employee.all, :id, :empLastName, :prompt => "Select worker" %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Projects show
<%= button_to "Assign!", new_employee_project_path(project_id: #project.id) , class: "btn btn-primary", :method => :get %>
Does anyone have any ideas on how to fix this?
In your controller try changing puts params[project_id] to puts params[:project_id].
params is a Hash so you must refer to its keys with symbols, that is :project_id. project_id is just a variable that has no value assigned to it, hence the error undefined local variable or method 'project_id' for #.
UPDATE ("Couldn't find Project with 'id'=" fix)
The button in projects' show view is not sending the parameter project_id even though you are passing it to the new_employee_project_path helper (check your url string and you will see it ending at ? with no parameters). To fix it, i recommend using a regular form instead of button_to helper.
So, instead of this line:
<%= button_to "Assign!", new_employee_project_path(project_id: #project.id) , class: "btn btn-primary", :method => :get %>
Try using this form:
<form action="<%= new_employee_project_path %>" method="get">
<input type="hidden" name="project_id" value="<%= #project.id %>">
<input type="submit" value="Assign!" class="btn btn-primary">
</form>

remove subdomain from form

I'm using a constraint to set a subdomain for pages in my app
get '/', to: 'referal#new', constraints: { subdomain: 'keystrategy' }
It brings me to keystrategy.[mypage]. This page only contains a few lines :
<%= form_for #referal, url: {action: "create", subdomain: false} do |f| %>
<%= f.text_field :referer %>
<input type="hidden" value="keystrategy">
<%= f.submit "Valider" %>
<% end %>
But when I try to load this page, I get the following error :
No route matches {:action=>"create", :controller=>"referal", :subdomain=>"keystrategy"}
What am I missing ? I thought the subdomain: false would prevent this
use this code:
<%= form_for #referal, url: referal_url(subdomain: false) do |f| %>
<%= f.text_field :referer %>
<input type="hidden" value="keystrategy">
<%= f.submit "Valider" %>
<% end %>
Ok, so I found out it was not about the form itself, but rather because of routing. When using a subdomain, every new route generated by
resources :whatever
assumes you're doing so in your current subdomain. Therefore, if subdomain.yousite.com points to a view including a form, the form will be handled by subdomain.yoursite.com/whatevers, as a POST request.
So, you have to make sure that this route includes your subdomain. In your routes.rb file, add these lines:
get '/', to: 'whatever#new', constraints: { subdomain: 'yoursubdomain' }
post '/whatevers', to: 'whatever#create', constraints: { subdomain: 'yoursubdomain' }
Your form should look like this :
<%= form_for #referal do |f| %>
<%= f.text_field :referer %>
<input name="referal-type" type="hidden" value="keystrategy">
<%= f.submit "Valider" %>
<% end %>
And you're all set.

Parameters not passing in url in form

I am using rails 4 and rspec 2. I have a simple_form which sends an email.
<%= simple_form_for #student, url: create_message_pro_users_path(student_id: #student), method: :get do |f| %>
<%= f.input :subject, input_html: { size: 59 } %>
<%= f.input :message, as: :text, input_html: { class: 'text_block' } %>
<%= f.button :submit, 'Update' %>
<% end %>
In the test environment, this routes to the create_message action in the pro_users controller with params[:student_id] and params[:student], i.e. it works as I would expect.
In my development environment, this routes to the correct action with the params[:student], but does not have a params[:student_id], i.e. it does not work.
If I look at the browser source code, the relevant section is
<form novalidate="novalidate" class="simple_form edit_student" id="edit_student_1847" action="/pro_users/create_message?student_id=1847" accept-charset="UTF-8" method="get"><input name="utf8" type="hidden" value="✓" />
What is going wrong and why is it working in my tests but not the actual browser. My solution at present is to refactor the action into my student controller, where I can just use standard routing. However, I use BDD so it is disconcerting when the request spec passes but it does not work in the browser!

simple_form delete method instead post method

In simple_form is possible to use the http delete verb instead the default post verb?
<%= simple_form_for #object , method: :delete do |f| %>
<%= f.input :instance_name, as: :check_boxes, collection: #roles %>
<%= f.button :submit %>
<% end %>
It doesn't works.
Unfortunately simply stating that it doesn't work is not helpful in understanding the problem you're seeing, but I'll make a guess based on my own initial confusion with the "method:" parameter. Most browsers don't support PUT and DELETE methods, so what simple_form_for does is generate a form with a POST method, but it also adds a hidden field to pass the actual method. So:
simple_form_for #service, url: service_path, method: :delete
generates:
<form action="/services/6" method="post">
<input name="_method" type="hidden" value="delete" />
....
Rails uses that to call the correct controller method. Hope that helps.

Rails submit_to_remote can't POST

I'm trying to nest a form within another using submit_to_remote but it does a PUT instead of a POST. Can anyone explain what's wrong here?
The routes are RESTful:
map.resources :thing
map.resources :item
The view is like this:
<% form_for(#thing) do |f| %>
<% fields_for(Item.new) do |i| %>
<%= i.text_field :name %>
<%= submit_to_remote 'create', 'Create', :url => items_path, :method => "post" %>
<% end %>
<%= f.text_field :title %>
<%= f.submit 'Update' %>
<% end %>
To get around the problem I've been adding another method to the restful routes to do a create on a PUT but it's ugly and I want to know what the problem is.
The submit_to_remote comes out as:
<input name="create" onclick="new Ajax.Request('/items', {asynchronous:true, evalScripts:true, method:'post', parameters:Form.serialize(this.form) + '&authenticity_token=' + encodeURIComponent('blah')});" type="button" value="Create">
Thanks
How about using link_to_remote instead and style the link to like a 'button', or just leave it as a link would be fine to be honest. This way you can control the XmlRequest fully. Currently I think the method is being determined by your actual form that is being submitted by the JS, not the :method your setting in the helper call.

Resources