clever universal form partials in rails - ruby-on-rails

I have a widget for currencies which I use throughout my application. Ie. the user changes the currency from EUR -> USD, or about 13 other currencies. I have a few other use-cases such as dates but this one is the easiest to explain. Currency basically just updates a session variable by calling the currency controller and then uses some JS to reload the page, but I'd like to only fetch certain elements of the page (ie that reflect the currency change and nothing else)...
$("#places_list").html("<%= escape_javascript(render :partial => 'places/list') %>");
or if another controller
$("#locations").html("<%= escape_javascript(render :partial => 'locations/places') %>");
but these elements are specific to the current controller, ie rendering a controller specific partial such as a list... (the currency math itself is in a an application helper, so no new logic is going on), and the currency controller is simple a partial loaded by different controllers. (Locations, Places, etc)
Other than making an action in every controller specific for this purpose, how can I make it behave in a way that I can render elements specific to the current controller, so I can replace them intelligently over js, instead of reloading? Ie. I can pass in to currency the current controller
<%= hidden_field_tag :info, controller.controller_name %>
I'm not sure if any of that makes sense, but I hope it does, at least in my own brain if not in anyone else's.

I have tried a little app and below would be a one solution for you,
first of all, in my case what I'm trying to do is to have an attribute called :info in each model , so that I can call it (<%= f.text_field :info %>) in my views (please note f can be any instance of a model)
for that I need to add :info attribute to each model. You have several ways of doing it
1 - create a class (which inherits from AR::Base and inherit all the other models from the given class) (but it requires some code changes)
2 - Quick and ugly way is to inject my :info attribute to AR::Base class (Which I did ;) )
create a file in config/initializers say curreny.rb and add this code
module ActiveRecord
class Base
attr_accessor :info
end
end
after that from any view which u uses AR, will have the :info attribute
Ex: users/new
New user
<% form_for(#user) do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.label :info %><br />
<%= f.text_field :info %>
</p>
<p>
<%= f.submit 'Create' %>
</p>
<% end %>
<%= link_to 'Back', users_path %>
Please note: this is not a very good solution, but I think with this you can start thinking
cheers
sameera

Related

Storing user input value in controller

I have a controller named Welcome with view called index.
In my index view i have created a small form as such.
<%= form_for :location do |f| %>
<%= f.label :Longitude %><br>
<%= f.text_field :integer %>
<br>
<br>
<%= f.label :Latitude %><br>
<%= f.text_field :integer %>
<p>
<%= f.submit %>
</p>
<% end %>
In this form the user can enter some integer value for longitude and latitude. Once the user enters value for longitude and latitude. They click submit. Upon submit i would like to store these values in my controller. So i am using the following method where i have two instance variables taking values from the form.
def index
#long = params[:longitude]
#lat = params[:latitude]
end
In my routes.rb I have
get 'welcome/index'
post 'welcome/index'
Please tell me where i went wrong. Also if someone can suggest a better way of doing this also i would appreciate it i am new to rails and i want to learn the correct way of doing things so i don't create bad habits early on.
The reason it's not working is because your fields are both named :integer, and since they share the same name, the browser will only send one value.
So, with your code, if you filled in the first field with 'a' and the second with 'b', your params would contain something like this:
{ location: { integer: "aaa" } }
Which obviously isn't what you want! If your HTML looked more like this (I've stripped the layout stuff to make things clearer):
<%= form_for :location do |f| %>
<%= f.label :longitude %>
<%= f.text_field :longitude %>
<%= f.label :latitude %>
<%= f.text_field :latitude %>
<%= f.submit %>
<% end %>
Then you could access the params in your controller params[:location][:longitude] and params[:location][:latitude]
A good idea to see the difference between the effect of your form vs this form would be to inspect the html. Take a look at the input name attributes, and label for attributes and see how they match up with the params Rails receives. Also, when you post the form, be sure to look in your server log to see the params! :)
After reading your question, I think you want to see how controllers, views and models work. For learning purpose you can generate scaffold and study the generated code.
For example, generate a model GeoLocation, related controller and views by this:
rails g scaffold GeoLocation longitude:string latitude:string
Now fire up rails server and browse http://localhost:3000/geo_locations/new and save your long, lat. I wrote this answer to give you some guidance.
You can follow these excellent books:
The book of Ruby
The Rails 4 Way

Is it possible to access a controller's instance variable in a partial if the partial is being rendered by a different controller's view?

Hi guys thanks in advance for the help. I am building a sort of online game using rails. The user interface is all supposed to be centered around one page: users/... I am running into an issue in creating and interacting with objects outside of users. For example, within the user page users are supposed to have the ability to create a fortress. The fortress of course is its own object with its own model and controller. If I were to try to put a form to create a fort using the form_for tag in the users page, the form wouldn't be able to access the fort controller's #fort instance variable and would throw an error. In my attempt to solve the problem I have created a partial view for forts called _new.html.erb containing the fort form
Here it is:
<h1>Create a New Fort</h1>
<%= form_for(#fort) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :ownership %>
<%= f.text_field :ownership %>
<div style="display:none;">
<%= f.label :xco %>
<%= f.text_field :xco %>
<%= f.label :yco %>
<%= f.text_field :yco %>
<%= f.label :territory %>
<%= f.password_field :territory %>
</div>
<%= f.submit "Create a Fort" %>
<% end %>
I then render that partial in my user show.html.erb here:
<%= render "forts/new" %>
Of course moving the form to a partial does nothing at all, but what I was hoping to do was something along the lines of this:
<%= render partial: "new", object: #fort %>
I would like to pass the fort instance variable into the partial then render the partial in the users view. I recognize however that the variable passed to the partial as described above comes directly from the view the partial is rendered in, and at that realization I am at a loss for ideas.
I have considered the key might be somewhere in associations and I have been crawling the internet for info on that. My models are set up so a user has_many forts and a fort belongs_to a user. I don't know whether or not that will help.
All help is appreciated,
Thanks loads,
Alex P
From your outer view, assuming #fort has been instantiated in your controller, you can pass #fort directly to your partial like this:
<%= render 'forts/new', :fort => #fort %>
I think what you are looking for is accepts_nested_attributes_for. This RailsCast explains how it is used.
In your case you would add accepts_nested_attributes_for :forts to your user model. I'm not sure what your user/show view looks like, but you should just be able to add a <%= f.fields_for :forts do |f| %> which would contain the fields currently in forts/new.
Yes, you can pass Locals with render statements wherever you call partial.
<%= render 'shared/error_messages', :locals => {:info => first, :img_style => "original"} %>

How to use AJAX with multiple nested forms? "The Gym Plan" problem

I want to be able to fill a table with some data through AJAX. My problem is that this data is from two different models. This will be long but please bear with me.
Imagine an application that would fill the plan for working out at the gym (clearly not an application for me :D). This plan has many routines (per type basis or day basis) which has many steps to go through.
Is it possible to use AJAX to fill a nice table that fills dynamically? Ideally I would prefer to save and display a table each time the user fills any new data.
What I have so far:
In the models I added the accepts_nested_attributes_for property.
I am using nested_form that allows us to add and remove nested models.
Let's take a look at our form:
app/views/plans/_form.html.erb
<%= nested_form_for #plan, :url => plan_path(#plan), :html => { :class => :form } do |f| %>
<%= f.label :name, "Plan Name" %>
<%= f.text_field :name %>
<%= f.fields_for :routines do |r| %>
<%= render 'routine_fields', :f => r %>
<% end %>
<%= f.submit %>
<%= f.link_to_add "Add a routine", :routines %>
<% end %>
So fields_for allows us to save many routines inside a plan, NICE! Let's define our fields views:
app/views/plans/_routine_fields.html.erb
<%= f.label :name, "Routine Name" %>
<%= f.text_field :name %>
<%= f.fields_for :steps do |s| %>
<%= render 'step_fields', :f => s %>
<% end %>
<%= f.link_to_add "Add a step", :steps %>
<%= f.link_to_remove "Remove this routine" %>
app/views/plans/_step_fields.html.erb
<%= f.label :name, "Step Name" %>
<%= f.text_field :name %>
<%= f.link_to_remove "Remove this step" %>
This works great! We can add as many routines inside a plan and many steps inside a routine we are able to create a complete plan in one view.
BUT IS UGLY! and also very confusing! So my problem again: How would I update the table each time the user fills any new data?
Ideal:
One approach that you could use for this would be to break up the form into different forms that are loaded via ajax, and just continuously update attributes on a model. You could also just use the form that you have now and break up the html so that it doesn't all show in a table.
For dealing with forms, you could check out the railscast on wicked
For dealing with ajax, there is a very good railscast on ajax/jquery
You could also break up this logic into different partials, and change the UX a bit, so that a user still has the same functionality, but it lives on a different view. You can add ajax to this by following the previously mentioned ajax railscast or using the turbolinks gem (though turbolinks is a bit different).
It seems to me that this is primarily a UX problem, and you're trying to crowbar a particular implementation into a rigid UX. I would try reframing the UX to see if there is a more elegant solution to the problems you have mentioned.

Rails alternative to including active record call in view

I have a form partial that looks like this:
<%= form_for(#pool) do |f| %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :tournament %><br />
<%= f.collection_select :tournament_id, Tournament.active, :id, :name, :prompt => true %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
This seems like a code smell because the view shouldn't be responsible for knowing how to get the data for the <select> tag. The alternative to have the controller assign an instance variable is problematic because I have to replicate that code in several actions depending on whether or not this form is rendered.
In ASP.NET MVC I'd just pull that field out into a partial view and display it with a call to RenderAction Which would evaluate a common controller action. However, in Rails render :action => '/view' seems to only allow full blown views to be rendered. I'm pretty new to Rails so I'm not sure about what the best practices are.
You can do a helper method as coder_tim suggests, but in my opinion that still leaves data access in the view.
The controller is the proper place for this and if you're worried about duplication, set up a before_filter that only acts on the actions that need this collection:
before_filter :get_active_tournaments, :only => [:new, :edit]
for example.
Hope this helps.
I like the smell of that code :) Simplicity over extremism. Less files = less methods to worry = cleaner code.
However, there are times when a dropdown is used too many times in your application, and it's a little more complicated than just calling a scope. In that cases, I write a helper.

Difference between form_for , form_tag?

What is the difference between form_for and form_tag? Is anything different for form_remote_for and form_remote_tag?
You would use form_for for a specific model,
<% form_for #person do |f| %> # you can use f here
First name: <%= f.text_field :first_name %>
Last name : <%= f.text_field :last_name %>
<% end %>
Form_tag create basic form,
<%= form_tag '/person' do -%>
<%= text_field_tag "person", "first_name" %>
<% end -%>
form_for prefers, as its first arg, an activerecord object; it allows to easily make a create or edit form (to use it in a "new" view you should create an empty instance in controller, like:
def new
#foo = Foo.new
end
It also passes a form variable to the block, so that you don't have to repeat the model name within the form itself. it's the preferred way to write a model related form.
form_tag just creates a form tag (and of course silently prepare an antiforgery hidden field, like form_for); it's best used for non-model forms (I actually only use it for simple search forms or the like).
Similarly, form_remote_for and form_remote_tag are suited for model related forms and not model related forms respectively but, instead of ending in a standard http method (GET, POST...), they call an ajax method.
All this and far more are available for you to enjoy in the FormHelper and PrototypeHelper reference pages.
EDIT 2012-07-13
Prototype has been removed from rails long ago, and remote forms have completely changed. Please refer to the first link, with reguard to the :remote option of both form_for and form_tag.
These should be similar:
<% form_for #person do |f| %>
<%= f.text_field :name %>
<% end %>
and:
<%= form_tag '/person' do %>
<%= text_field_tag "person[name]" %>
<% end %>
If you want to submit the same params to the controller, you would have to define this explicitly.

Resources