I'm trying to create a collection_action where I'm going to do something with the entire collection of filtered items. My problem is that from within the collection_action I don't seem to have access to the filtered collection. When I access collection it is only the items that are on the first page of records. In my action_item I have access to collection_before_scope which is exactly the filtered record I want, but this is empty when I try to access it from within my collection_action.
Below is my current setup attempting to find the correct collection.
collection_action :dosmth, :method => :get do
# collection_before_scope will be empty
puts "collection_before_scope = " + collection_before_scope.to_yaml
# collection will return only the filtered items on the front page
puts "collection = " + collection.to_yaml
redirect_to :back, notice: 'Something happening'
end
action_item :only => :index do
# collection_before_scope will return the full collection that I'm looking for.
puts "collection_before_scope = " + collection_before_scope.to_yaml
link_to "Export", dosmth_admin_earned_points_path(controller.params)
end
The closest related question I could find was this, ActiveAdmin Collection action on filtered data, which didn't seem to help me out.
Any help would be greatly appreciated.
Thank you,
Update:
I still have the same problem, but I have figured something out. If I try to access the collection before the collection_before_scope then the correct filtered items are in collection_before_scope. I don't want to have to access the collection just to get the correct collection_before_scope though. Not sure why this would happen.
collection_action :dosmth, :method => :get d0
# collection will return only the filtered items on the front page
puts "collection = " + collection.to_yaml
# collection_before_scope will be correct because I accessed the collection first. why???
puts "collection_before_scope = " + collection_before_scope.to_yaml
redirect_to :back, notice: 'Something happening'
end
Try this:
puts "filtered collection = " + apply_filtering(collection).to_yaml (before you call collection)
Why do you reach the correct filtered collection after you accessed the collection first?
The collection method will invoke the find_collection method: https://github.com/activeadmin/activeadmin/blob/master/lib/active_admin/resource_controller/data_access.rb#L32
The find_collection method will invoke the apply_filter method: https://github.com/activeadmin/activeadmin/blob/master/lib/active_admin/resource_controller/data_access.rb#L50
And once the collection method has been called:
https://github.com/activeadmin/activeadmin/blob/master/lib/active_admin/resource_controller/data_access.rb#L22-L27
I know this is old, but I just ran into this issue when trying to access the filtered collection for a custom CSV download.
Because ActiveAdmin uses Ransack for search, you can grab the filtered collection using their params.
ModelName.ransack(params[:q]).result worked for me.
Related
I am developing a site that will use the shoppe gem as the e-commerce engine, and I am having trouble adding or deleting an item to an existing order. A user should be able to view their order, and then next to each order item, there will be a plus sign and a minus sign. When clicked, the plus sign should add one item of the same kind to the order, and likewise, the minus sign should delete an item when clicked. I have two links with the following code:
link_to "+", adjust_order_item_quantity_path(item.id), :method => :post
link_to "-", adjust_order_item_quantity_path(item.id), :method => :delete
My routes look like this:
post 'orders/change_item_quantity/:order_item_id', to: 'orders#change_item_quantity', :as => 'adjust_order_item_quantity'
delete 'orders/change_item_quantity/:order_item_id', to: 'orders#change_item_quantity'
The code for my orders controller is:
def change_item_quantity
item = current_order.order_items.find(params[:order_item_id])
request.delete? ? item.decrease! : item.increase!
if item.quantity == 0
redirect_to "#", :notice => "#"
else
redirect_to request.referer
end
rescue Shoppe::Errors::NotEnoughStock => e
respond_to do |wants|
wants.html { redirect_to request.referer }
end
end
Much of this code is the sample code given on the shoppe tutorial site, but I am just having trouble getting it to work correctly. When I click the '+', I get an error that says:
Couldn't find Shoppe::OrderItem with 'id'=[nil] [WHERE `shoppe_order_items`.`order_id` = ?]
When I click the '-', one item is deleted as it should be, but then I get the same error message as above when I click the '-' when there is only one item left. I would really appreciate the help!
Thanks in advance!
EDIT
Here is my application trace:
1 def change_item_quantity
2 item = current_order.order_items.find(params[:order_item_id])
3 request.delete? ? item.decrease! : item.increase!
4 if item.quantity == 0
5 redirect_to root_path
The problem is on this line:
item = current_order.order_items.find(params[:order_item_id])
It looks like your order_item_id param is getting lost at some point. In general you should
include the full error trace with your question because it will tell you which line of code
caused the error.
Having some experience with reading errors, though, I can tell you that the
Couldn't find <ModelName> error is generally caused by using find with a bad id.
So the following line is what's failing:
item = current_order.order_items.find(params[:order_item_id])
Your view code looks good to me and I'm not sure what you'd need to change to
fix this error. What I'd do it put a breakpoint at the beginning of your change_item_quantity
method and make sure that params[:order_item_id] is set. If it's not, it's probably
an issue with your view code (the link_to).
Perhaps the item.id is nil in your link. Check your HTML and make sure ERB has entered the
ID correctly.
I am very new to Rails, I want to be able to insert names into an array attached to my user.
I added an empty array called 'subscribed_tasks' to my 'schema.rb'
And I wondered how I can push data into that array.
My first attempt was:
Having '= link_to "Subscribe", subscribe_task_path, class: "btn btn-default"' in my show.haml and then having this within my route.rb:
resources :tasks do
member do
get :subscribe
end
end
& then adding this to my Tasks_Controller:
def subscribe
#user = current_user
#user.subscribed_tasks << #task.title
redirect_to #task, notice: "Subscribed to "+ #task.title
end
The problems I'm facing are:
How do I pass the task they're subscribing to's parameters to the controller so then the correct data can be pushed into the array. Also, I don't think I'm finding the array correctly.
All in all, what I'm programming is a mess, am I missing something fundamental about Rails and is there an entirely better way to solve this problem?
So I have a search form that returns a Kaminari paginated array. The first page always returns a list of results, however the "GET" of all subsequent page links returns no results and I'm not sure why!
Here are my search methods in my controller
def writer_search
#writers = Kaminari.paginate_array(#results).page(params[:page]).per(10)
end
def writer_search_submit
#results = #my big array of results, this part works fine
#writers = Kaminari.paginate_array(#results).page(params[:page]).per(10)
render 'writer_search'
end
View Code
=form_tag(writer_search_submit_path, :method => 'post') do
%input{:name => 'keywords', :id => 'keywords', :value => params[:keywords]}
= submit_tag "Search"
- #writers.each do |writer|
#show the results
= paginate #writers
Server Log when clicking a pagination link
Started GET "/editors/writer_search?commit=Search&keywords=business&page=2"
Processing by EditorsController#writer_search as HTML
Parameters: {"commit"=>"Search", "keywords"=>"business", "page"=>"2", "utf8"=>"✓"}
The first rendered page has the first 10 results of my array (in this case, there are hundreds of results). Clicking on any of the pagination links makes a GET and returns a page with no results.
Any ideas?
Looks like you have #results defined in writer_search_submit but not writer_search.
The GET request to "/editors/writer_search?commit=Search&keywords=business&page=2" goes through EditorsController#writer_search where #results is undefined (and so you get a page with no results).
Update: (Thanks Thilo)
Perhaps you could use a before_filter to load #results for all the actions that need it?
Rails doesn't render the search results on an actually search page but on the default index page of whatever route you're searching for.
I am currently trying to define my first new action in Rails 3, despite various problems I think things are almost done now. However, I as a final hurdle I am struggling to send the correct parameter value to my function...
My function is defined in items_controller:
def clickcountplusone
clickeditem = Item.find(params[:id])
redirect_to clickeditem.externalurl if clickeditem.update_attribute(:click_count, clickeditem.click_count + 1)
end
routes.rb contains:
match '/items/clickcountplusone', :to => 'items#clickcountplusone'
and the view contains:
<%= link_to image_tag( item.picture.to_s + ".gif", send("items_clickcountplusone_path", item.item_name)%>
The view page itself loads correctly (the one with the link on it), but when I click on the link I get an error:
Couldn't find Item with ID=clickcountplusone
{"id"=>"clickcountplusone",
"format"=>"whatever the name is"}
and rather than going to the external page, my browser tries to load:
http://localhost:3000/items/clickcountplusone.whatever the name is
Can anyone tell me how I should be calling the function so that the ID is the item_name and the external URL is visited rather than an incorrect one on my site?
Thanks in advance
It seems like this would be a normal route, instead of a RESTful route (this is fine). There are some places you have to change.
First, in your controller's action, you used params[:id] which is not set actually.
In this particular case, I would suggest you use params[:item_name] instead of id because you are really sending the item_name.
def clickcountplusone
clickeditem = Item.find_by_item_name(params[:item_name])
redirect_to clickeditem.externalurl if clickeditem.update_attribute(:click_count, clickeditem.click_count + 1)
end
Item.find could only be used if the parameter is one of the actual id / :all / :first / :last.
You are finding by the item_name, so you should use Item.find_by_item_name instead.
Second, you have to update you route too (or else you would need something like /you_path..?item_name=blahblahblah which is fine too if you don't mind)
get 'items/:item_name' => 'items#clickcountplusone', :as => :items_clickcountplusone
Third, you view. IMO, most of the time if you are using send but not writing library / really back end code, you probably misusing it.
<%= link_to image_tag("#{item.picture.to_s}.gif"), items_clickcountplusone_path(:item_name => item.item_name) %>
You don't have any variable in your match statement. Try something like
match '/items/clickcountplusone/:id', :to => 'items#clickcountplusone'
and
<%= link_to image_tag(item.picture.to_s + ".gif", items_clickcountplusone_path(:id => item.item_name))%>
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. :)