How to “dynamically add options” to 'form_for'? - ruby-on-rails

I am using Ruby on Rails 3.2.2. In order to implement a "dynamic generated" AJAX style file upload form I would like to "dynamically add options" to the FormHelper#form_for statement if some conditions are meet. That is, at this time I am using code as-like the following (note that I am using the merge method in order to add options to the form_for method):
<%
if #article.is_true? && (#article.is_black? || && #article.is_new?)
form_options = {:multipart => true, :target => "from_target_name"}
else
form_options = {}
end
%>
<%= form_for(#article, :remote => true, :html => {:id => "form_css_id"}.merge(form_options)) do |form| %>
...
<% end %>
However, I think that the above code is too much hijacked.
Is there a better way to accomplish what I am making? For example, can I access from view templates some (unknown to me) instance variable named as-like #form and "work" on that so to change related options as well as I would like? Or, should I state a helper method somewhere? How do you advice to proceed?
BTW: Since the upload process is handled by using a HTML iframe, I am using the remotipart gem in order to implement the AJAX style file upload form - I don't know if this information could help someone...

This looks like a good candidate for a helper method. In your view:
<%= form_for(#article, :remote => true, :html => article_form_options(#article, :id => "form_css_id")) do |form| %>
...
<% end %>
In app/helpers/articles_helper.rb
module ArticlesHelper
def article_form_options(article, defaults = {})
extras = if article.is_true? && (article.is_black? || article.is_new?)
{ :multipart => true, :target => 'form_target_name' }
else
{}
end
defaults.merge(extras)
end
end
Helpers are a good place to keep logic that's too complex for a view but still related to the view.

Related

Manage link in a partial file in Ruby On Rails

In one of my application I have multiple scopes (admin, trader, manager, seller)
In each scope, I'd like to show the same page (exemple : show a seller) but in this page I've got link to edit the seller :
- admin_edit_seller_path(#seller)
- trader_edit_seller_path(#seller)
The page is exactly the same except for the link.
How can i manage that ?
Thanks
In this particular case you can use Rails' Polymorphic Routes
For example:
new_polymorphic_path(#manager) # => "/managers/new"
edit_polymorphic_path(#seller) # => "/sellers/1/edit"
polymorphic_path(#trader, format: :json) # => "/traders/1.json"
Or in your case, with scopes, you could use this form:
edit_polymorphic_path([:admin, seller]) # => "http://example.com/admin/sellers
polymorphic_path([:trader, seller]) # => "http://example.com/trader/sellers
Which means you can use this in a view:
<%= render partial: 'shared/my_partial', locals: {scope: :admin, object: #seller} %>
And this in your partial:
<%= link_to edit_polymorphic_path([scope, object]), [scope, object] %>

Passing local variable to a partial in rails 2.x

I have the following method in my controller:
def update_fees_collection_dates_voucher
#batch = Batch.find(params[:batch_id])
#dates = #batch.fee_collection_dates
render :update do |page|
page.replace_html "fees_collection_dates", :partial =>"fees_collection_dates_voucher"
end
end
the method calls the following partial in _fees_collection_dates_voucher.html.erb file:
<%= select :fees_submission, :dates_id, #dates.map { |e| [e.full_name, e.id]},{:prompt => "#{t('select_fee_collection_date')}"},{:onChange => "#{remote_function( :url => {:action => "load_fees_voucher"},:with => "'date='+value+'&batch_id='+#batch.id") }"} %>
The partial makes a remote call to the load_fees_voucher method when a selection list value is selected or changed. However, I'm unable to pass the information in the #batch instance variable (from my original method) to the remote method via the partial. If I change the #batch.id to a hard-coded value in the last line (under :with) the code runs fine but not in the current format. Is there a different procedure to access instance variables in partials ? Thanks!
You can use the same instance variable in the partials.
Try this,
<%= select :fees_submission, :dates_id, #dates.map { |e| [e.full_name, e.id]},{:prompt => "#{t('select_fee_collection_date')}"},{:onChange => "#{remote_function( :url => {:action => "load_fees_voucher"},:with => "'date='+value+'&batch_id='+#{#batch.id}") }"} %>

Syntax to route Rails form_for to custom controller

Have tried forums, documentation and blog suggestions. They converge on syntax that for me does not properly save AND route through desired controller.
Big picture, I have two software applications that share functionality. To implement shared functionality, I had Rails generate Shared::Widgets. This MVC works just fine. No problem viewing, updating, creating, or deleting using standard shared/widgets & etc routing.
Then, for the product-specific functionality, I created two controllers: Product1::Widgets and Product2::Widgets. Both inherit from Shared::Widgets controller. Both are empty except for product-specific layouts.
This scheme almost works. When I route to product1/widgets, it sets layout to product1 and invokes index method of shared/widgets. The result is display of shared/widgets/index.html.erb with product1 layout. Similarly, when I route to product2/widgets, this sets product2 layout and invokes index method of shared/widgets. The result is display of shared/widgets/index.html.erb with product2 layout. Perfect.
But now we get to the form_for. Because it implements the rails magic, it really really wants to route directly to Shared::Widgets controller. But that's not what I want. I want it to route to the appropriate product controller so as to set layout. The rails generated form_for was something like this:
form_for(#shared_widget, :html => { :class => "form"}) do |f|
I tried:
form_for([:product1, #widget], :html => { :class => "form"}) do |f|
but that duplicates namespace (product1_widget_shared_widget_path).
I tried the following three formats, all of which seem to route correctly, and save the record, but the record is empty (columns are blank):
form_for(#widget, url => "product1/widget", :html => { :class => "form"}) do |f|
form_for(#widget, url => url_for(:controller => "widget"), :html => { :class => "form"}) do |f|
form_for(#widget, url => url_for(:controller => "widget", :action => "create"), :html => { :class => "form"}) do |f|
Any help? If the above code has spelling errors, it is due to transcription. The actual code I used passed the interpreter. Thank you.
try this
form_for(url: { controller: "posts", action: "create" }, html => { :class => "form" }, method: "post") do |f|

What is the Rails convention for sending form data to a URL dependent on form value?

I would like a form submitted at the url
/index/fruit
to submit the form data to
/index/:identifier
where :identifier is determined by a value of the form
What is the rails convention in this instance?
Is there a way to achieve this without a controller level redirect or javascript-updating the submit URL?
routes.rb
match 'smasher(/:action(/:id))', :controller => "customcontroller", :as => :smasher, :defaults => { :action => :index, :id => :fruit }
index.html.erb
<%= semantic_form_for :d, :url => smasher_path, :html => { :method => :get } do |f| %>
... form data ...
<%= f.input :identifier, :as => :hidden %>
<% end %>
My current implementation is similar to this answer
There's isn't really a "convention" for this, but rather one of those things where there's more than one way to do it.
One way that you could do it is still send the form to one and only one action within the controller, but then delegate in the controller which action to go to, like this:
def smasher
if params[:identifier] == 'this'
smash_this!
else
smash_that!
end
end
def smash_this!
# code goes here
end
def smash_that!
# code goes here
end
Heres the javascript version (though technically its all on an erb html template), if you're feeling up to it.
<%= f.input :identifier, :as => :hidden, :onchange => "$(this).setAction()" %>
<script>
// While you can this script block here within your erb template
// but best practice says you should have it included somehow within `<head></head>`
$(function() {
//create a method on the Jquery Object to adjust the action of the form
$.fn.setAction = function() {
var form = $(this).parents('form').first();
var action = form.attr('action')
form.attr('action', action.substr( 0, action.lastIndexOf('/')+1 ) + $(this).val());
}
});
</script>
Heres the pure javascript version:
$(function() {
//create a method on the Jquery Object to adjust the action of the form
$.fn.setAction = function() {
var form = $(this).parents('form').first();
var action = form.attr('action')
form.attr('action', action.substr( 0, action.lastIndexOf('/')+1 ) + $(this).val());
}
//we gotta bind the onchange here
$('input[name="identifier"]').change($.fn.setAction);
});

Ruby on Rails: form_for works, but remote_form_for doesn't

<% remote_form_for(#media, :url => url_for(:controller => :attachments,
:action => :add_from_disk, :object_id => #object),
:html => { :multipart => true, :id => 'new_media', :onsubmit=>'unsaved_changes = false' } ) do |f| %>
but if I change the remote_form_for to form_for, I don't get this error:
ActiveRecord::RecordInvalid (Validation failed: Document file name must be set.):
Why would it work with form_for, but not the AJAX version?
You can't upload a file using AJAX.... You'll need to implement a flash uploader to send files in the background. It's not pretty, but Uploadify is pretty cool
Recommend keeping file uploading as regular form for.
Or you can use the jQuery form plugin, which works great. In this case you'd do a normal form_for, and inside of your javascript file (once you've included jquery and the jQForm lib in your html) you'd do something like this:
$(function() {
$("#myFormDomID").ajaxForm({ iFrame : true });
});

Resources