Hey. I think I am in a mind trap here. I am using Rails 2. In the index view of my controller I set up something like
def index
#posts = Post.all
end
so that I can use #posts in my index, e.g. each-do. Id like to pass #posts to a custom made view, in where I can use the same variable again. This I want to do over a link from the index view. Something like that:
link_to "newpage", {:controller => 'posts', :action => 'newmethod', :param => #posts}
What I have created so far is a new method in my Post controller. A new view. And and a new route to that site. Any suggestions? thx for your time
You're going to have to collapse those values into something that will fit in a URL, then decode them later. For instance:
# Put this in your helper method module PostsHelper
def post_ids
#posts.collect(&:id).join(',')
end
Your adjusted link would be:
link_to "newpage", {:controller => 'posts', :action => 'newmethod', :param => post_ids }
When you fetch the next page you'll need to decode these by retrieving them again:
#posts = Posts.find(params[:param].split(/,/))
There's no way to pass an instance variable between requests because they are explicitly cleared out.
As a note, try and use the generated route methods instead of the hash-style declaration. You would probably have a route already listed in rake routes:
# Instead of { :controller => 'posts', :action => 'new', :param => post_ids }
new_post_path(:param => post_ids)
These generated methods are much more readable in practice and have the advantage of being configurable later if you want to re-interpret what they mean by adjusting your routing table.
Another note is that if the list of IDs gets very large, you may not be able to encode them into a URL as the limit is about 1500 bytes. You may instead have to serialize the conditions used to generate the list in the first place and then re-run those again later. So long as you're dealing with tens of items and not hundreds you should be okay, though.
In your controller
def newmethod
#posts = Post.all
end
You can't pass all your models in a link ! The #posts var in the index action disappears after the request
I know that store arbitrary data in session is not a best practice, but in some cases this approach is simple and easy.
In your controller:
def balabala
#...
session[:your_var] = "this is the var used in another view&action!"
# ...
end
In any other pages:
<%= session[:your_var] %>
That's it. ugly, not MVC at all. :) Only recommended for very rare cases. :)
Related
Knowing these things
model_sym = :users
user_id = 1
I can do this:
url = "#{model_sym.to_s}/#{user_id}"
But is there a way I could do something like this?:
url = url_for(model_sym, user_id)
I could first "find" the user to pass into url_for, but I'd rather not.
I think you could use polymorphic_url:
polymorphic_url([model_sym, user_id])
Resources
Having written that, it seems you're getting confused about the resourceful nature of Rails.
Built on Ruby, Rails is object-orientated, which means that everything you do needs to be tied to an object (model):
The reason why this is important is because all of Rails' helpers etc are built around objects. That's why when you create a new set of routes, you can simply call resources (as resourceful is to give the object a set of attributes / methods you can call)
--
Implementation
The problem you have is you're not basing your routes around any objects - you're simply
calling symbols / numbers. Although this will work, it's not the "right" way to create Rails functionality
Your ideal situation is to build objects, and pass them to the routing structure of your application. To build an object, you'd do the following:
#user = User.find params[:id] #-> builds object
<%= link_to "Users Path", #user %> #-> pulls route from object
Something like this:
url_for(:controller => model_sym.to_s, :action => :show, :id => user_id)
You can do send("#{ model_sym.to_s.singularize }_path", id) to get the URLs you want.
This would call user_path(1) in your example.
First of all I'm newbie to rails
I have a controller like this one. The queries are working fine.
class StoreController < ApplicationController
def men_clothing
#men_clothing=Category.find_by_name("clothes").products.where(product_type: "men")
#men_clothing_tshirt=Category.find_by_name("clothes").sub_categories.find_by_name("t-shirt").products
end
Now I have a view for men_clothing in which I'm able to show all the products in #men_clothing instance variable by iterating over it.
But in my home page I have a links which I want to direct to #men_clothing_tshirt instance variable such that clicking on that link will show all the products of this instance variable.And if there is another link it should direct to a different instance variable.
How should I achieve this? Or suggest a alternative way to do this. Do explain how it works.
I know I can do that by making separate actions for each instance variable and making a view for it. But in that case I will have to make a lot of views.
Maybe you could try something similar to this link?
[:tshirt, :pant, :banana_hammock].each do |category|
get "mens_#{category}/:id", :controller => :mens, :action => :show, :type => category, :as => "mens_#{category}"
end
Then you'll get your paths that you're looking for, e.g. mens_tshirt_path, mens_pant_path, etc.
In your controller, you would change the action to change based on the incoming 'type'
class MenController < ApplicationController
before_filter :find_clothing_by_category
private
def find_clothing_by_category
#clothing = Clothes.where(category: params[:type].to_s)
end
end
your link is not redirecting to your instance, its redirecting to your action. so you have to define a new method for new link_to that, and define your #men_clothing_tshirt object in that method like this:
def your_method
#men_clothing_tshirt=Category.find_by_name("clothes").sub_categories.find_by_name("t-shirt").products
end
and in your link_to redirect to your_method:
link_to "Tshirt", your_method_path
Hope it will help.Thanks
i'm new of rails. I use rails 3.0.5 .
I have an EMPLOYEE resource, but I would like to manage it with another extern controller (emp_profile_controller).
This extern controller (emp_profile_controller) manages some actions (index, new_employee, create_employee, edit_employee, update_employee ecc.. ) .
My routes for this controller are :
controller :emp_profile do
get 'emp_profile' => :index
get 'emp_edit_profile' => :edit_employee
put 'emp_edit_profile' => :update_employee
get 'new_employee' => :new_employee
post 'new_employee' => :create_employee
get 'emp_list' => :emp_list
end
How can i use one form to handle both Create and Update actions in this controller ?
I tried with :
form_for(#employee, :url => { :controller => "emp_profile"}) do |f|
but it doesn't work.
If i manage only one action at time (create OR update), url_for works, for example :
form_for(#employee, :url => { :controller => "emp_profile", :action => "update_employee" }
but how can i handle both actions with one form ?
Thanks for your availability and I apologize if I asked a stupid question.
EDIT
For now, i solved checking if object exist in the form file, if exist i set a variable with the UPDATE action path, else, i set a variable with the CREATE action path. So in the form_for statement i use url_for with the above variable.
<% if #employee.new_record?
action = "create_employee"
method = "post"
else
action = "update_employee"
method = "put"
end
%>
form_for(#employee, :url => { :controller => "emp_profile", :action => action }, :method => method
I don't think it is the best way but it works and i can use only one form file.
As your model name and controller name are different, you can add this line to your routes
resources :employees,:controller=>"emp_profile",:path=>"emp_profile"
Change the method names of create_employee,update_employee to create and update respectively.
And change your form_for as given below
<%= form_for #employee do |f| %>
....
<% end %>
First of all, if you want to update something, this object should exist.
How do plan to find it out, I don't know (cause there different ways, depends on background).
There are 2 ways of solving this issue.
You can just check if object exist in view file, and if exists, renfer form for update, else for create.
Other way is to do it in controller.
For example:
def create
#employee=Employee.find_by_name('Jack Black') #for example
if #employee!=nil
render :action=> 'update'
else
#employee=Employee.new(:employee)
#employee.save
end
as i understand you want to execute two different actions on the same controller using a form submitting, this is not possible, you can only execute one action using a form submitting,
because the form is reaching to an action controller that action is suppose to render some view at the end of it's execution code, if it was possible to use to actions on form submitting how rails will know which view to render??? (that's why it's not possible).
if you want to do some more code execution at the controller, the right way to it is to call a method with some code in it that you want to execute, that method should be in the model,
because it is a good practice to write all massive chunks of code in the model and leave the controller as light from code as possible :-)
hope this helps.
I have a problem where I need values passed in from a GET request and I don't know how to set up the routing definition.
My Category object has a type(string),a color(string) and many products. I want to create a simple web service that lets the caller get all of a Category's products by passing in the Category's type and color:
http://www.myapp.com/getProducts?catType=toy&color=red
or ?
http://www.myapp.com/categories/getProducts?catType=toy&color=red
How do I define the correct routing for this situation? Are there better ways to do this in a Restful manner... because I know that Rails is Restful, so if there is a way to do it "correctly" then that would be even better.
Thanks
Your first example:
map.getproduct '/getProduct', :controller => 'your_controller', :action => 'your_action'
In controller you will have catType and color in params hash:
params[:catType]
=> 'toy'
params[:color]
=> 'red'
Is there better way? Probably yes, but it depends on your needs. If you will always have catType and color parameters, than you can add route like this:
map.getproduct '/getProduct/:catType/:color', :controller => 'your_controller', :action => 'your_action'
You will have access to those parameters with params hash like in previous example. And your urls will look like this:
www.myapp.com/getProduct/toy/red
If your parameters may change, you can use route globbing:
map.getproduct '/getProduct/*query', :controller => 'your_controller', :action => 'your_action'
Then it will catch all request that has www.my.app.com/getProduct/... at the begining. But you will have more work in controller. You will have access to query with this:
params[:query]
and for www.myapp.com/getProduct/color/red/catType/toy it will give:
params[:query]
=> ['color', 'red', 'catType', 'toy]
So you have to parse it manualy.
One RESTful way to to do this would involve a product resource nested beneath a category resource, like so:
http://www.myapp.com/categories/toy/products?color=red
Your routes.rb would need to contain:
map.resources :categories do |category|
category.resources :products
end
Since my url above using the Category's type attribute for routing, I'm implying that each type is unique, like an id. It'll mean that whenever you're loading a category in the Categories controller (or anywhere else) you'll need to load the category with Category.find_by_type(params[:id]) instead of Category.find(params[:id]). I like routing categories this way whenever possible.
Your ProductsController controller index action would find products using lines like:
#category = Category.find_by_type(params[:category_id])
#products = #category.products.find(:all, :conditions => { :color => params[:color]} )
Remember, your Category model must contain the line:
has_many :products
It's probable a good idea to enforce that in the model with validations:
validates_presence_of :type
validates_uniqueness_of :type
To make routing work you should also overwrite the to_param method in the Category model to return type instead of id:
def to_param
self.type
end
I'm not sure if I'm missing a known design pattern, but I keep coming up against the following problem with RESTful routes Rails.
In my example, I have a users controller that can respond in javascript (:js) format. The default response populates a page element with a list of the paginated users:
# /app/controllers/users_controller.rb
class UsersController < ActionController
def index
#users = User.paginate(:all, :page => params[:page], :conditions => ['name ILIKE ?', params[:name])
respond_to do |format|
format.html
format.js
end
end
end
The corresponding RJS template would look like:
# /app/views/users/index.js.rjs
page.replace_html :users, :partial => 'users'
This works fine, allowing me to perform AJAX lookups on users. However, in another part of my site (say the user editing form) I would like to perform an AJAX lookup of users, but update a set of ''select'' options or perform an inline autocomplete, rather than update the #users page element, e.g.
# /app/views/users/edit.html.erb
<%= f.text_field :name %>
$('#user_name').autocomplete({url: '/users', data: 'name=value', ...})
My question is what would be the best DRY way to achieve this? I don't think I should need to create a new controller action to correspond to the different view, as this would involve repeating the finder code. The only solution I've come across so far is to build some javascript conditions into my RJS helper:
# /app/views/users/index.js.rjs
page << "if($('#users').length > 0)"
page.replace_html :users, :partial => 'users'
page << "else"
page.replace_html :user_options, :partial => 'user_options_for_select'
This feels very brittle, and unclean for Rails. Am I missing something in how I can respond with different views depending on the calling controller?
Appreciate any help!
Chris
In one of them you have a list of users and the other one a list of options.
So even though for now, your two pages are having the same feature, they're independent from each other and you might want to change things for only one of them in the future.
So I'd keep them distinct with two different javascript actions . It'll will allow you to much more easily make them evoluate on their different path.
Anyway as you can see, they're already quite different. You have two different partials and two different html tags id.
Trying to have the same code for them both here seems quite confusing to me.
So yes I'd create two actions, one for the users list and one for their options.