Rails submit_to_remote can't POST - ruby-on-rails

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.

Related

Rails form_for sending params to controller action and not model

In the controller review_queue I have a custom action that posts a result to a target URL, I want to build a form for this action. I am not going to save any of the fields to the DB I am just going to pass them in the params to the post_review action.
def post_review
RestClient::Request.execute(:method => :post,
:url => Rails.application.secrets['target_url'],
:content_type => :json,
:payload => #result_params.merge!(params[:reasons]).to_json,
:headers => HEADERS)
end
In the view I have a form that will be filled out and on submit it should send up the reasons when the form is submited, I am setting the review_queue_id and the status in the form, since these are static, but the reasons should come from the textarea
<%= form_for(:review_queue, url: { action: 'post_review', :review_queue_id => #review_queue.id, :status => 'accepted'} ) do |f| %>
<div class='form-group'>
<label for='comment'>Please give a reason? (required)</label>
<%= f.text_area(:reasons, placeholder: 'Your commentns ...', rows: 9, class: 'form-control') %>
</div>
<div class='modal-footer'>
<%= f.submit 'Approve', class: 'btn btn-success btn-decission btn-modal-left-side' %>
<button type='button' class='btn btn-default' data-dismiss='modal'>Close</button>
</div>
<% end %>
error message:
NoMethodError - undefined method `reasons' for #<ReviewQueueApplication:0x007fa7ff7832d8>:
It seems as if rails is assuming the MVC architecture here, and assuming I want to pass the reasons to the review_queue model. there is no reasons column so it's dropping a no method error. Is there a way of specifying that the form is 'temporary' and only getting as far as the controller?
This seems like it should be a simple thing but there is some rails magic happening here.
NoMethodError - undefined method `reasons' for
ReviewQueueApplication:0x007fa7ff7832d8
form_for assumes that you are creating a form for a model object and expects the fields to be present in that specific model's table(in a normal situation).
You should be going with form_tag
<%= form_tag post_review_path, method: :get, :review_queue_id => #review_queue.id, :status => 'accepted'} ) do |f| %>
<div class='form-group'>
<label for='comment'>Please give a reason? (required)</label>
<%= text_area_tag(:reasons, placeholder: 'Your commentns ...', rows: 9, class: 'form-control') %>
</div>
<div class='modal-footer'>
<%= submit_tag 'Approve', class: 'btn btn-success btn-decission btn-modal-left-side' %>
<button type='button' class='btn btn-default' data-dismiss='modal'>Close</button>
</div>
<% end %>
And in the controller access it like params[:reasons]. Also if you noticed, I've added method: :get to the form_tag as you don't want to save the info to DB
The rails helper form_for is used for forms for rails resources. You want to use the form_tag helper. Search for form_for and form_tag here for more information on these 2 methods.

Rails 3: form_for missing closing </form> tag

I am using a form_for in one of my views in my rails app, but for some reason the closing tag is not being generated, and this will be handled safely in most browsers, except IE 8 and lower.
Here's some sample code:
<%= form_for object, :remote => true, :url => remote_update_path, :html => {:name => "form_#{id_number}", :id => "form_#{id_number}"} do |f| %>
<%= hidden_field_tag "field_a", object[:field_a] %>
<ul class="class1">
<li> <%= f.check_box :field_b, :class => "class2", :id => "b" %> B</li>
<li> <%= f.check_box :field_c, :class => "class2", :id => "c" %> C</li>
</ul>
<% end %>
For some reason this isn't generating the closing </form> tag where <% end %> is located. (I know there is now submit button in the form, this does not affect the missing </form>.)
Is this a bug? or is there something that I'm doing wrong?
This is almost certainly happening as a result of invalid HTML somewhere on the page. Run it through the validator, until it's all passing, and I bet the problem goes away...
I had the same issue. It happened to me because I didn't close one div tag properly inside the forms.

Rails feedback form: How to get the url for the current page?

I am working with David Francisco's rails feedback plugin. The plugin works fine, except for one thing - I would need the feedback form to submit to the database the url for the page where the feedback form was used. Does anyone know how to do this?
The view that would need to send the current url, in addition to the currently sent information:
<h4>Feedback</h4>
<p>Please leave us feedback, it's really appreciated.</p>
<%= form_for #feedback, :as => :feedback, :url => feedback_index_path, :html => { :id => "feedback_form" } do |f| -%>
<%= f.hidden_field 'user_id', :value => current_user.id %>
<% unless #error_message.blank? %>
<p class="error">
<%=h #error_message %>
</p>
<% end %>
<p>
<%= f.label 'subject' %>
<%= f.select 'subject', ['Problem', 'Suggestion', 'Question', 'Other'] %>
</p>
<p>
<%= f.label 'comment' %><br />
<%= f.text_area 'comment', :rows => 10, :cols => 30 %>
</p>
<p><%= f.submit 'Send' %></p>
<% end -%>
Currently, feedback_index_path is always '/feedback', the url for the form.
Thank you,
Alexandra
You can use request.referer in your controller to get the path of the page that called your action. request.referer returns a full url but you can parse it with the URI module:
URI(request.referer).path
I see some people have suggested request.fullpath but this is actually the path of the action that's processing the request (in your case /feedbacks/new) and not the path where the form was submitted from.
If request.fullpath doesn't work incorrectly, you can make a quick hack, storing page url in data-attributes of page, and on submit get current url by jQuery from that attributes.
But it is a hack, just to make it working.
BTW how do you render feedback form?
feedback_index_path is a routes helper method that will always return the same thing. In your case /feedback.
Look here for info on accessing the current URL in both Rails 2 and 3.

How to use form_tag to update params

I have been struggling with a problem in Rails for a couple of days and still could not find the solution. Could you help me with that?
Problem: I have a search box that puts a :search_string entry in the params structure. I use a form_tag for that and it works fine.
<% form_tag :controller=> 'items', :action => 'find' do %>
<%= text_field_tag :search_string, params[:search_string] %>
<% end %>
The problem is when I want to add and update other params key-value (in another view), for instance :start_date, to filter the search_string result. Here is the code snipped that I use in the view:
<% form_tag :controller=> "items", :action => "find", :params => params do %>
<%= hidden_field_tag :date_start, '2010-04-01' %>
<%= submit_tag 'April' %>
<% end %>
<% form_tag :controller=> "items", :action => "find", :params => params do %>
<%= hidden_field_tag :date_start, '2010-03-01' %>
<%= submit_tag 'March' %>
<% end %>
When I first click on "April" submit button, then the params is correctly passed to the controller (i.e. there is a params[:start_date]='April'). However when I try to click "March" button afterwards, the params[:start_date] is not updated. I definitely think this is a stupid newbie mistake, but I cannot figure out how to properly use the form_tag. Could you tell me if I am doing something work? Otherwise, could you advise me which is the best way to update the params using form_tag's ? Thank you very much in advance.
Miquel
What you may want to do is instead force-merge the parameters, something along the lines of:
<% form_tag :controller=> "items", :action => "find", :params => params.merge(:date_start => '2010-03-01') do %>
<%= submit_tag 'March' %>
<% end %>
There is a chance you're inadvertently submitting two of the same parameter and the first of them is getting picked, but since the "first" is not clearly defined, you may get inconsistent results.
Have a look in your log file to see what parameters are received from the two forms.

Multiple links on a Rails view that each perform different actions - how best to handle this?

One of the things I'm doing includes several links on the show view. For instance, I have a link (or button) for "Accepting", and another one for "Rejecting". Click on Accept, and the model updates the is_accepted field as true, click on Reject, and the is_accepted field is false.
Now, how best do I handle this? In ASP.NET, I would have simply created a LinkButton and written a handler, but Rails doesn't work that way, so I'm trying to figure out how to essentially replicate what a LinkButton would do.
Right now, I'm coding two forms on the same view, nearly identical, that look like this:
<%= form_for #thing do |f| %>
<%= hidden_field_tag 'thing[is_accepted]', '1' %>
<%= f.submit "Accept" %>
<% end %>
<%= form_for #thing do |f| %>
<%= hidden_field_tag 'thing[is_accepted]', '0' %>
<%= f.submit "Reject" %>
<% end %>
This feels weird to me, but I can't seem to find anything that says this is the wrong way to do it.
I could, I assume, dry things up by using a partial and/or a helper method, but I wanted to make sure I'm on the right track and not doing something totally wrongly.
You can give your submit tag a name.. ie
<%= form_for #thing do |f| %>
<%= hidden_field_tag 'thing[is_accepted]' %>
<%= f.submit "Accept", :name => 'accept' %>
<%= f.submit "Reject", :name => 'reject' %>
<% end %>
Then you can detect the name in params[] and skip the '1'/'0' value.
I think you're going about it the right way. One way to clean up your forms is by using the model form helpers all the way through, so you'd end up with something like
<%= form_for #thing do |f| %>
<%= f.hidden_field :accepted, :value => true %>
<%= f.submit "Accept" %>
<% end %>
<%= form_for #thing do |f| %>
<%= f.hidden_field :accepted, :value => false %>
<%= f.submit "Reject" %>
<% end %>
But other than that, it looks like the right way to go about it. I would suggest against creating new methods to do this, because you're not doing anything outside of normal web requests (updating a model in this instance).
Using the submit tag as the switch and detecting it in params[] is also a good way, but I usually prefer to keep my controllers as vanilla as possible. In the end, both of these ways would end up with the same amount of 'stuff' in the UI, so whichever style you'd rather use should be fine.
Depending on how you want your UI to work you might consider link_to_remote (part of the prototype helper) - you can specify an action, params etc, and have it return some JS that gets run.
If you're using map.resources in your routes.rb you should be able to do something like this:
map.resources :things, :member => {:accept => :get, :reject => :get}
Then in your controller:
def accept
#thing = Thing.find(params[:id])
#thing.is_accepted = true
#thing.save
end
def reject
#thing = Thing.find(params[:id])
#thing.is_accepted = false
#thing.save
end
And finally in your view:
<%= link_to 'Accept', accept_thing_url(#thing) %>
<%= link_to 'Reject', reject_thing_url(#thing) %>
Or if you are using Ajax:
<%= link_to_remote 'Accept', :url => accept_thing_url(#thing) %>
<%= link_to_remote 'Reject', :url => reject_thing_url(#thing) %>

Resources