How to remember a parameter value between pages in a controller - ruby-on-rails

I have managed to produce a series of three buttons on an index page enabling a user to identify a subset of the objects in a database - button 1 - type = "new", button 2 - type = "used", button 3 - no restriction i.e. can be new or used.
Currently index.html.erb contains:
<%= link_to "New", :controller => params[:controller], :action => params[:action], :product_type => 'New' %>
<%= link_to "Used", :controller => params[:controller], :action => params[:action], :product_type => 'Used' %>
<%= link_to "Don't Restrict", :controller => params[:controller], :action => params[:action], :product_type => nil %>
Within product.rb i have:
scope :by_product_type, lambda{|product_type| where(:product_type => product_type) unless product_type.nil? }
Finally I have productfinder_controller:
before_filter :load_grips, :only => [:index, :bybrand, :bycolour, :byprice]
protected
def load_products
if params[:product_type]
#productssmatchingtype = Product.by_product_type(params[:product_type])
else
#productsmatchingtype = Product
end
end
The above code works exactly as I hoped, loading all items initially and restricting them if Button 1 or Button 2 is pressed.
I would also like to have similar functionality on 3 other pages within the Productfindercontroller, namely byprice, bybrand and bycolour. I have put the same code as provided above in each of these 3 other .html.erb files and again things seem to be behaving...
EXCEPT - When a new page is loaded the default is that all the products are shown, i.e. it has not remembered what button the user pressed on the previous page. Is it possible to store the information regarding the button pressed somewhere which is accessible to all the pages in the controller? Similarly / Alternatively, is it possible to define #productsmatchingtype (in productfinder_controller) in such a way that it is accessible to all the pages and doesn't need to start from scratch again?

You cannot remember variables beetwen requests. However you can store product_type in session:
def load_products
#get product_type from session if it is blank
params[:product_type] ||= session[:product_type]
#save product_type to session for future requests
session[:product_type] = params[:product_type]
if params[:product_type]
#productssmatchingtype = Product.by_product_type(params[:product_type])
else
#productsmatchingtype = Product
end
end
That should do the job.

Related

undefined method `each' for "#<Complaigns::ActiveRecord_Relation:0x00000003cfb4c8>":String

I have a model, called Complaign, with some other attributes along with the date of complaign (c_date).
In the ComplaignController, I have an index view, which displays all the complaigns. There is a filter which takes from date and to date. On filtering that, it works fine, and properly displays the complaigns fired on those dates.
Now I want the result of this query to be passed on to a different method, say export method.
I thought of passing this from the index view, since it is stored in #complaigns.
This is my index method:
def index
if params[:from] && params[:to]
from = params[:from].to_date
to = params[:to].to_date
#complaigns = Complaigns.where(:c_date => from..to)
else
#complaigns = Complaigns.all
end
end
In the index view, this is what I have written
<%= link_to "Export", {:controller => "complaigns", :action => "export", :complaigns => #complaigns}%>
This is the export method
def export
#complaigns = params[:complaigns]
end
Now, in the export view, when I do the follwing line:
#complaigns.each, I get this error--
undefined method `each' for "#<Complaign::ActiveRecord_Relation:0x00000003cfb4c8>":String
Now this is because, I think, there is no method each in String class. Is there any way, I can convert the String to Complaign type in the method export or while passing it from the index view, pass it as Complaign object instead of String? Is there any other way of doing this?
You can't pass Ruby on Rails model objects directly in the controller parameters, you can pass their corresponding ids and then load the models from the database. HTTP / Ruby on Rails is stateless. If you always go to index before export, one way how to solve this might be:
<%= link_to "Export", {:controller => "complaigns", :action => "export", :complaigns => #complaigns.map(&:id)}%>
def export
#complaigns = Complaigns.find(params[:complaigns])
end
It looks like #complaigs is passed as string instead of actual active_record relations object. You should calculate #camplaigs in export instead of sending them. Or you can pass array of ids
#complaigns.collect(&:id)
HTTP is stateless protocol, which means each request is independent from the other (unless you use cookie or session). For your export method, it knows nothing about the result of index method unless you pass enough information to it. So a simple solution can be:
index view
<%= link_to "Export", {:controller => "complaigns", :action => "export", :from => params[:from], :to => params[:to] }%>
export method
def export
if params[:from] && params[:to]
from = params[:from].to_date
to = params[:to].to_date
#complaigns = Complaigns.where(:c_date => from..to)
else
#complaigns = Complaigns.all
end
end
Here, the parameters for index is passed to export.
But this method is not DRY enough. You can consider using index for export like this:
def index
if params[:from] && params[:to]
from = params[:from].to_date
to = params[:to].to_date
#complaigns = Complaigns.where(:c_date => from..to)
else
#complaigns = Complaigns.all
end
if params[:export].present?
render 'export'
else
render 'index'
end
end
Then in your export link, you can use this:
<%= link_to "Export", {:controller => "complaigns", :action => "index", :from => params[:from], :to => params[:to], :export => true }%>
PS. These codes are not tested. Just for demonstration purpose.
You can't do what you are trying to do. The problem is that when the view is rendered, the resulting HTML is text, and therefore #complaigns is turned into it's equivalent text (the same as #complaigns.to_s).
To do what you want, you need to pass to your link, the same paramaters you used to create #camplaigns in your index view. So:
Change your link to:
<%= link_to "Export", {:controller => "complaigns", :action => "export", :to => params[:to], :from => params[:from]}%>
And then change your export method to:
def export
index
end

How to make a custom route in Rails? By custom I mean one that reacts to params

So essentially I've setup a route to match "products/:product", which seems to respond to a page like baseurl/products/toaster and displays the toaster product. My problem is I can't seem to use link_to to generate this path, and by that I mean I don't know how. Any help on this?
There are several solutions on this one :
<%= link_to 'Toaster', { :controller => 'products', :action => 'whatever', :product => 'toaster' } %>
But it's not really Rails Way, for that you need to add :as => :product at the end of your route. This will create the product_path helper that can be used this way :
<%= link_to 'Toaster', product_path(:product => 'toaster') %>
Within your routes file you can do something like:
match "products/:product" => "products#show", :as => :product
Where the controller is ProductsController and the view is show
within the Products controller your have
def show
#product = Hub.find_by_name(params[:product])
respond_to do |format|
format.html # show.html.erb
end
end
Where whatever is in the products/:product section will be available via params.
Then, since we used :as in your routes you can do this with link_to:
<%= link_to product(#product) %>
Where #product is an instance of a product or a string. This is just an example and the param can be anything you want, the same goes for controller/action. For more info you should check out this.
Hope this helps!

Want to add links to a method of another controller in the show screen using active admin

in my active admin app i have 2 models, per example: Vehicle and Front.(Front has many Vehicles)
In the :show view of an Front, it lists all the vehicles that belong to it. And for each Vehicle it lists, it have a link "Remove" that removes the corresponding Vehicle from that Front. Here's what my code looks like:
ActiveAdmin.register Front do
show do
panel "Vehicles in this Front" do
table_for(front.vehicles) do |vehicle|
vehicle.column("id") {|vehicle| auto_link frente.vehicles}
vehicle.column("category") {|vehicle| vehicle.descricao}
vehicle.column("status") {|vehicle| vehicle.status}
vehicle.column {link_to "Remove" , remove_admin_vehicle_path(vehicle.id), :method => :post}
end
end
And the Remove method from Vehicle:
member_action :remove , :method => :post do
vehicle = Vehicle.find(params[:id])
vehicle.front = null
vehicle.save!
flash[:notice] = "vehicle removed"
redirect_to :action => :show
end
But when I click on the Remove link, theres an error: Its not sending the id from the vehicle. How can I send the id from the Vehicle?
Use delete method and destroy action, it's right way.
so..
Try to use
vehicle.column {link_to "Remove" , remove_admin_vehicle_path(vehicle), :method => :post}
And show rake routes result.

Custom Settings Form in ActiveAdmin

I'm using rails-settings by Squeegy from https://github.com/Squeegy/rails-settings as well as Activeadmin. What I'm trying to accomplish is making a form in ActiveAdmin that I can let the site admin change the settings for the site, which take a command line syntax of:
Setting.foo = "bar"
Setting.site_title = "My Awesome Site!"
Setting.max_users = 35
I really don't think I've got too far, but I'm already stuck. I'm up to the point of having a custom ActiveAdmin form made:
ActiveAdmin.register_page "Settings" do
action_item do
link_to "View Site", "/"
end
content do
form do |f|
#Inputs for Settings
end
end
end
But I don't even know how to begin laying out the form to directly access the Settings model, or how to make a custom controller to handle the input. I suppose if I could get the input sent to a controller that I could make, I'd be just fine.
This is very simple to do with ActiveAdmin.
Lets say your settings class is Settings :
ActiveAdmin.register_page "Settings" do
content do
table :class => 'settings' do
thead do
th 'Setting'
th 'Value'
th ''
end
Settings.all.each do |key, val|
tr do
td strong key
td val
td do
link_to "delete", admin_settings_delete_path( :key => key ), :method => :post
end
end
end
tr do
form :action => admin_settings_create_path, :method => :post do
td do
input :name => 'key'
end
td do
input :name => 'val'
end
td do
input :type => 'submit', :value => 'Add'
end
end
end
end
end
page_action :create, :method => :post do
Settings[params[:key]] = params[:val]
redirect_to :back, :notice => "#{params[:key]} added"
end
page_action :delete, :method => :post do
Settings.destroy params[:key]
redirect_to :back, :notice => "#{params[:key]} deleted"
end
end
Of course you'll need to add some CSS and maybe some validations but you have your settings page.
Edit:
Note that I wrote this for rails-settings-cached, not rails-settings, but my quick search led here so I guess this could still help someone.
I don't think you want your site's form to directly change the settings in ActiveAdmin, I would ...
Create a new table, eg. adminsettings and add fields for each of the settings you want to store for instance site_title, alternatively you could use each row for a setting which means you can add new settings in the future without changing the database
Put together a form in Activeadmin to maintain your settings
Add some functions to your model to grab the settings so you can do something like ..
Setting.site_title = Adminsetting.getsitetitle
You could be clever with your model method and use the method_missing facility so you need the least amount of code to get a setting ...
class << self
def method_missing(method, *args, &block)
setting = Adminsetting.where(:code => method.to_s).first
if setting
return setting.content
else
return super(method, *args, &block)
end
end
Perhaps you could package this into a Gem as it could be a useful thing for others.

Rails pass data to form for different model

I have two models, Users and Shifts.
Users: id, name
Shifts: user_id, time_length
User has_many Shifts; Shift belongs_to User. Fairly simple.
What I want to do is add a button on my show user controller (/users/1) that links to the new Shift controller view (/shifts/new). I've managed to do this with a button, as I want to pre-populate the form with the information from my Users model (i.e. send across the user.id).
I'm using the following code, which is linking fine, but can't work out how to pass the user.id details
button_to "Create Shift", {:controller => "shifts", :action => "new"},{ :method => "get"}
You can pass in extra parameters to the second argument like so:
button_to "Create Shift", { :controller => "shifts", :action => "new", :user_id => user.id }, { :method => "get" }
This should generate a URL like /shifts/new?user_id=5.
You can use Nested resources:
In routes.rb write:
map.resources :users do |users|
users.resources :shifts
end
Then the path for the new shift form would be new_user_shift_path = /users/:id/shift/new
And in the shifts_controller you can get the user like this:
#user = User.find(params[:user_id])
Then you put it in your form as a hidden tag field. (Or it won't be necessary - I don't know exactly)

Resources