I made custom index view for ActiveAdmin, and I would need to get the admin path for the given collection.
Here is what I have:
module ActiveAdmin
module Views
class IndexAsSpecial < ::ActiveAdmin::Component
def build(page_presenter, collection)
//...
// should be something like /admin/posts
path_to_collection = ???
//...
end
def self.index_name
"special"
end
end
I have searched and tried, but all I found is paths for a resource, not for the collection (e.g. resource.route_collection_path )
I also found this, but here I am still missing the right parameters, or maybe the class name of the active admin collection:
Rails.application.routes.url_helpers.polymorphic_path([:admin,:posts])
Just that I need to replace :posts somehow dynamically.
Any ideas?
I must say, that the documentation of ActiveAdmin is very vague here, but after debugging a bit more I found the answer to my question:
helpers.collection_path # will generate /admin/posts
or if you need a member action on the collection:
helpers.resource_path(:action_name) # will generate /admin/posts/action_name
Related
I have an ActiveAdmin resource whose collection requires some particularly complex queries to avoid a bunch of n+1's. I tried to modify controller#scoped_collection with all the proper .includes or .joins, but it was still doing n+1's.
I've since changed to an approach of just doing the queries by hand and dumping the relevant results into Hashes. Then in my index view, I grab the data from the hashes, rather than from the scoped_collection.
Unfortunately, I can't figure out how to make an instance variable available in the index scope. I got around that by putting it into the params hash (which is available in the index scope), but that ends up breaking the filtering.
So, is there some way I'm not seeing to scope variables from inside scoped_collection or some other sort of before_filter-like method that will be available inside index?
Sample code:
ActiveAdmin.register ComplexResource do
actions :index
controller do
def scoped_collection
#complex_collection_relation = ComplexResource.where(crazy: :stuff)
# a bunch more lines of code to do avoid n+1's and put info into supporting data hash
#supporting_data_hash = {}
complex_collection_relation.each{|r| supporting_data_hash[r.id] = stuff }
# my hacky workaround because #supporting_data_hash isn't available below
params[:supporting_data_hash] = #supporting_data_hash
return #complex_collection_relation
end
end
filter :my_filter_that_gets_broken, as: :string
index do
column :name
column :complex_attribute_1 do |r|
params[:supporting_data_hash][r.id][:complex_attribute_1]
end
# how can I do something like this without using the params workaround
# column :complex_attribute_1 do |r|
# #supporting_data_hash[r.id][:complex_attribute_1]
# end
end
end
I know this is an old question but it's the first one that comes up when googling. Also, I'm not 100% sure it applies to the duplicate question so I'll leave my answer here:
Instance variables can be reached as helpers when defining columns for a resource. E.g.:
ActiveAdmin.register Company do
controller do
before_action :load_data, only: :index
def load_data
#loaded_data = expensive_operation
end
end
index do
column 'Something' do |company|
loaded_data[company.id]
end
end
end
I found a reference to it on this answer on Github issues
#Jiemurat 's answer to this question is the solution. This question is duplicative of How do I use instance variables, defined in the controller, in the view with ActiveAdmin?
I am using ruby on rails to make a simple social networking site that includes different message boards for each committee of a student group. I want the url structure for each board to look like https://<base_url>/boards/<committee_name> and this will bring the user to the message board for that committee.
My routes.rb file looks like:
resources :committees, only: [:index]
match '/boards/:name', to: 'committees#index(name)'
My index function of committees_controller.rb file looks like:
def index(name)
#posts = Committee.where(name: name)
end
And then I'll use the #posts variable on the page to display all of the posts, but right now when I navigate to https://<base_url>/boards/<committee_name> I get an Unknown Action error, and it says The action 'index(name)' could not be found for CommitteesController.
Could someone guide me through what I have done wrong?
Once I get this working, how would I make a view that reflects this url structure?
Set up your routes like this:
resources :committees, only: [:index]
match '/boards/:name', to: 'committees#show'
and the controller like this:
def index
#committees = Committee.all
end
def show
#committee = Committee.find_by_name!(params[:name])
end
You can't really pass arguments to controller actions the way you were trying to with index(name). Instead, you use the params hash that Rails provides you. The :name part of the route declaration tells Rails to put whatever matches there into params[:name].
You also should be using separate actions for the listing of committees and displaying single committees. Going by Rails conventions, these should be the index and show actions, respectively.
When routing, you only specify the method name, not the arguments:
match '/boards/:name', to: 'committees#show'
Generally you will declare something with resources or match but not both. To stay REST-ful, this should be the show method. Index is a collection method, usually not taking any sort of record identifier.
Arguments always come in via the params structure:
def show
#posts = Committee.where(name: params[:name])
end
Controller methods that are exposed via routes do not take arguments. You may construct private methods that do take arguments for other purposes.
right now I am trying to generalize some of my code. So far it went well, I wrote a few mixins which I can dynamically add to Controllers or Models in order to get things done while obeying DRY.
But with my "Searchform-Helper" I hit a corner in which, right now, I am a bit clueless.
I have a mixin 'SearchIndexController' which adds the methods needed to search for data within a searchindex-table.
After including the mixin I can initialize search-actions within the according controller calling this method:
def init_searchaction(object, name=nil)
singular = object.to_s.classify
plural = singular.pluralize
name = "search_#{singular}".to_sym if name.nil?
unless self.respond_to?(name)
define_method(name) do
# init
success=false
#TODO
# >>> DRAW NEW ROUTE TO THIS ACTION <<<
# evaluate searchform input for Searchindex-Call
needle = params[:query]
success, x, notice = execute_search("#{singular}", needle)
# send selected/filtered data to page
respond_to do |format|
format.js {
render :update do |page|
page.call "sidx_updateSearchResultContentAtIdTag", "##{plural.downcase} tbody", "#{render x}" if success
page.call "sidx_updateNotice", success, "#{notice}"
page.call "sidx_stopSpinner"
end
}
end
end
else
logger.warn("#{__FILE__}:#{__LINE__}:#{self.to_s}: search-action for '#{self.class.name}' can not be created, it already exists!")
end
end
So lets say I have a User-Controller. Within the Userform I have the need to search for several objects. Lets assume I want to be able to search for users, departments and clients... with my mixin I'd just have to initialize the searchactions like this:
init_searchaction :user
init_searchaction :department
init_searchaction :client, :find_clients
these would create actions within the including controller that are called
search_user
search_department
find_clients
The only thing missing is a way to get a route for them. I don't want to have to define the route upfront. I just want to 'init_searchaction' and have the mixin create the necessary route.
So... would it be possible to add the route to the accoring search-action from withing the mixins init_searchaction method dynamically? I think the necessary code would be placed at the #TODO mark in the code example above. But I still haven't found out how to do it... I mean, actually I would be surprised if it would not be possible.
Would anyone have an idea as how to do this? Thanks in advance for any idea that leads to the solution!
You can add work around standart dynamic route
match ':controller(/:action(/:id(.:format)))'
change it to your goals and enjoy :)
When I visit http://my-application.com/posts/1 in my browser, Rails knows I'm looking for the Post with id = 1. How can I get my application to do this internally? I.e., I'd like a function (call it associate_with_resource) that takes a string containing a URL as its input and outputs the associated resource. For example:
>> associate_with_resource('http://my-application.com/posts/1')
=> #<Post id: 1, ... >
(I'd like to be able to use associate_with_resource throughout my application though -- not only in the console)
I think I'm looking for the ActionController::Routing::Routes.recognize_path method
You are right about ActionController::Routing::Routes.recognize_path and I would do it like this:
create a file lib/associate_with_resource.rb
module AssociateWithResource
def associate_with_resource(path)
url_hash = ActionController::Routing::Routes.recognize_path path
url_hash[:controller].classify.constantize.find(url_hash[:id])
end
end
class ActionController::Base
include AssociateWithResource
helper_method :associate_with_resource
end
class ActiveRecord::Base
include AssociateWithResource
end
Now you can call the associate_with_resource(path) from almost everywhere to get the resource belonging to a given path
When I visit http://my-application.com/posts/1 in my browser, Rails knows I'm looking for the Post with id = 1.
This is not correct.
In Rails 3, when you put this into routes.rb:
resources :posts
Then Rails will know that you have a controller named PostsController in the file app/controllers/posts_controller.rb. Rails will also know that in your PostsController class, you have seven methods that are intended to be action methods: index, new, create, show, edit, update, delete.
What you do in these action methods is entirely up to you. You may wish to retrieve and display a Post object, or not.
I am currently developing a blogging system with Ruby on Rails and want the user to define his "permalinks" for static pages or blog posts, meaning:
the user should be able to set the page name, eg. "test-article" (that should be available via /posts/test-article) - how would I realize this in the rails applications and the routing file?
for user-friendly permalinks you can use gem 'has_permalink'. For more details http://haspermalink.org
Modifying the to_param method in the Model indeed is required/convenient, like the others said already:
def to_param
pagename.parameterize
end
But in order to find the posts you also need to change the Controller, since the default Post.find methods searches for ID and not pagename. For the show action you'd need something like this:
def show
#post = Post.where(:pagename => params[:id]).first
end
Same goes for the other action methods.
You routing rules can stay the same as for regular routes with an ID number.
I personally prefer to do it this way:
Put the following in your Post model (stick it at the bottom before the closing 'end' tag)
def to_param
permalink
end
def permalink
"#{id}-#{title.parameterize}"
end
That's it. You don't need to change any of the find_by methods. This gives you URL's of the form "123-title-of-post".
You can use the friendly_id gem. There are no special controller changes required. Simple add an attribute for example slug to your model..for more details check out the github repo of the gem.
The #63 and #117 episodes of railscasts might help you. Also check out the resources there.
You should have seolink or permalink attribute in pages' or posts' objects. Then you'd just use to_param method for your post or page model that would return that attribute.
to_param method is used in *_path methods when you pass them an object.
So if your post has title "foo bar" and seolink "baz-quux", you define a to_param method in model like this:
def to_param
seolink
end
Then when you do something like post_path(#post) you'll get the /posts/baz-quux or any other relevant url that you have configured in config/routes.rb file (my example applies to resourceful urls). In the show action of your controller you'll just have to find_by_seolink instead of find[_by_id].