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!
Related
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.
I was going through instance-variable-vs-symbol-in-ruby-on-rails-form-for SO post.
As per the most voted answer
if you use symbol :post it creates
<form action="/posts" method="post">
if you use the instance #post
for #post = Post.new you will get
<form action="/posts/create" class="new_account" id="new_account" method="post">
But when I look at my rendered html page
<form action="/blogs/new" accept-charset="UTF-8" method="post">
<input name="utf8" type="hidden" value="✓" />
<input type="hidden" name="authenticity_token"
......
for the
new.html.erb
<%=form_for :blog do |f|%>
<%= f.text_field :title%>
<%= f.text_field :content%>
<%= f.submit :button %>
<% end %>
this throws me error saying
Routing Error
No route matches [POST] "/blogs/new"
Why is path mismatch occuring?
action url of form_for :blog will be the url render that form
action url of form_for "blog based on paths of that object (defined in routes) combine with state of that object
http://apidock.com/rails/ActionView/Helpers/FormHelper/form_for
When the model is
represented by a string or symbol, as in the example above, if the
:url option is not specified, by default the form will be sent back to
the current url
The answer you have linked is relatively old and I am fairly sure not accurate anymore.
The Rails way to do it is using instance variable.
You should then use <%= form_for #Blog.new do |f| =>. This should render as
<form action="/blogs" method="post">
For a resource, your form should be general for both show.html.erb and new.html.erb. In this instance, you should break your form into a partial _form.html.erb, and replace :blog with an instance variable:
_form.html.erb
<%=form_for #blog do |f|%>
<%= f.text_field :title%>
<%= f.text_field :content%>
<%= f.submit :button %>
<% end %>
Your controller actions should create this instance variable:
BlogsController
def new
#blog = Blog.new
end
def update
#blog = Blog.find(params[:id])
end
And, finally, your templates should just call the partial
new.html.erb
render partial: :form
update.html.erb
render partial: :form
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.
I have been recently working with Ruby on Rails and have run into an issue that I can not quite figure out. I need to create a bunch of form mockups, that do not function. That is they should have the submit button, but it should not do anything upon being clicked. Normally using html I would do something along the lines of
<form action="#">
</form>
Trying to convert this to use Rails form helpers, I have done the following
<%= form_tag "#" do %>
<%= label_tag :username, "Username: " %>
<%= text_field_tag :username %>
<br />
<%= label_tag :password, "Password: " %>
<%= password_field_tag :password %>
<br />
<%= submit_tag "Login" %>
<% end %>
This generates a form that is similar to what I want to achieve, however when clicking the submit button it tries to access /# via post which is not the desired result. Currently the only thing I can think of to achieve this is to set the disabled attribute of the button, but is there a better way?
Unfortunately this can't be achieved with form helpers. Defining a form_for or a form_tag requires an action for the form. You can set
:action => "#"
But this will require including the action in routes -> having a controller with action for it -> rendering some page yet again.
You could manipulate the form after loading with javascript however (sust remember to set :remote to true - ). Or alternatively, if you insist on using the form helpers - replace the submit_tag with a button_tag:
<%= button_tag "Login", :type => 'button'%>
Try
<% form_tag "#", :onSubmit => "return false" do %>
Have you tried with button_tag instead of submit_tag? See here. Just make sure you don't use the default, or you will be right back where you started.
I'm having a problem with Rails not POSTing anything in the params to an action.
I'm using a singular resource with a nested plural resource which may or may
not be where the problem is coming from (Rails has issues with form_for and singular
resource URLs).
Anyway, I have this in my routes:
resource :event do
resources :actions, :only => [:create], :controller => "events/actions"
end
The view:
<%= form_for([#event, Action.new], :remote => true) do |f| %>
<div class="field">
<%= f.label :team_id %>
<br />
<%= f.text_field :team_id %>
</div>
<div class="field">
<%= f.label :message %>
<br />
<%= f.text_field :message %>
</div>
<div class="field">
<%= f.label :score %>
<br />
<%= f.number_field :score %>
</div>
<br />
<%= f.submit "Update score" %> or <%= link_to "cancel", "#", :id => "cancel" %>
<% end %>
The create action:
def create
#event = Event.find(params[:event_id])
#action = #event.actions.create(params[:action])
end
Ok pretty standard no worries there.
But when I get the params from Rails nothing is there. :(
Params:
Started POST "/event/actions.4e67f09349ae71090c00000e"
Processing by Events::ActionsController#create as
Parameters: {"utf8"=>"Γ£ô", "authenticity_token"=>"stuff", "commit"=>"Update score"}
Completed 500 Internal Server Error in 31ms
What is going on here?
Edit:
If I remove the ":remote => true" line in my view,
I see that in my params I get one param ":format"
which appears to be the ID of the event.
However, I'm still not getting the action params. :(
Ideally I'd like to see those event & action models - I suspect that's where the problem lies. Without seeing those, a few suggestions:
Is 'accepts_nested_attributes_for :action' set in the event model?
Remove any 'attr_accessible' line from both models & see if things work. (Keep in mind you need to set accessible attributes for nested forms in the parent model)
'Action' seems like an imprudent name for a model. It's possible rails is overwriting 'action' methods with things related to the actual action
Hope this helps - I'd suggest posting the models if you still can't find a solution.