We have implemented gem 'rails_admin', '~> 1.4.3' in our application.
The issue we are facing here is in customizing the output values in the multi-select dropdown in rails admin.
For example: Student has many Teachers. So while creating a Student record we will have a multi-select dropdown of Teachers. Here we only want those Teachers who are in active state, not all the teachers.
To achieve the same, we have implemented something like below in the student_admin.rb file.
create do
field :name do
required true
end
field :teachers do
visible do
Teacher.where(state: 'active')
end
end
end
The above code neither gives any error nor filters the only active teachers.
Can someone help to get the expected result here.
Any suggestion will be highly appreciated.
There you go:
edit do
field :name do
required true
end
field :teachers do
associated_collection_scope do
proc { |scope| scope.where(state: 'active') }
end
end
end
Related
Say I have a model Post and a model Author, and an author has_many posts. Post also has a 'state' attribute and a scope, where I can filter by Post.where(state: 'active'). In RailsAdmin, I'd like to have two fields in the Author page: posts and active_posts, where active_posts are scoped to only associated posts with an active state. I've tried the following:
config.model 'Author' do
field :posts
field :active_posts do
formatted_value do
bindings[:object].posts.active
end
end
end
Obviously, this won't work because this just shows an ActiveRecord Association as the formatted value.
I've also tried defining an active_posts method on the Author model, and just calling field :active_posts for config.model 'Author', but that just returns an association as well.
On the other hand, something like on the wiki (https://github.com/sferik/rails_admin/wiki/Associations-scoping) for association scoping isn't working at all (the posts field is showing all associated posts, not posts within the scope). Additionally, this method would only give me one Posts field that would only show active posts.
config.model 'Author' do
field :posts do
associated_collection_cache_all false
associated_collection_scope do
Proc.new { |scope|
scope = scope.where(state: 'active')
}
end
end
end
Is there an alternative method?
I ended up simply creating a list of links:
field :active_posts do
formatted_value do
posts = bindings[:object].posts.active
posts.collect { |p| "<a href='/admin/post/#{p.id}'>#{p.title}</a>" }.join(", ").html_safe
end
end
I wish there were a prettier way, but this works too.
I'm trying to override the default ordering of the belongs_to drop-downs for the new/edit forms. I'd like to order the belongs_to relationships to name instead of the default id desc.
Based on the wiki (https://github.com/sferik/rails_admin/wiki/Associations-scoping) I have this:
field :theme do
associated_collection_cache_all false
associated_collection_scope do
Proc.new { |scope|
scope = scope.reorder("themes.name ASC")
}
end
end
end
The reorder seems to be ignored while where statements are picked up.
Are you sure the column you're trying to sort by is 'names' and not 'name'?
A good way to debug this would be to open a rails console and see if your reorder actually works this way.
Theme.all.reorder("themes.names ASC")
I'm guessing that probably won't work as expected and you need to tweak the reorder.
If you want to see the SQL it's creating, you can do this.
Theme.all.reorder("themes.names ASC").to_sql
That might give you more information about whats going wrong.
I am fairly new to active_admin, I was wondering if there is a way to achieve the following
I have two models
User
belongs_to :group
Group
has_many :users
I have successfully created pages in activeadmin for groups and users, now what I want is show users that belong to a certain group. I have button manage_members on groups index page which should show members of only that group. Where I can remove members from the group or add more members.
This is what I have been able to do so far
member_action :manage_members do
#group = Group.find(params[:id])
#page_title = "Manage Groups > ##{#group.name}, Edit Members"
end
and a the view app/vies/admin/groups/manage_users.html.arb
table_for assigns[:group].users do
column "Name" do |u|
u.user_id
end
column "email" do |u|
u.user.email
end
column "Created Date" do |u|
u.user.created_at
end
column "OfficePhone" do |u|
u.user.office_no
end
end
This shows the member of the groups, but I have to do all the work on this page to add edit delete a member, I cannot have active_admin filters and other cool stuff here, this is like a custom page,
Is there a way to have an index page (with all goodness of filters batch actions etc) ( like that of users ) but only showing users of a group. Something like a scoped index page which shows on users from a group and I have the same control over that page as any active admin index page ? More like the image below
rather than having to do all that work my self which currently looks like
Very new to active_admin so apologies if there something really straight forward that I am missing.
Thanks
Maybe a filter will do. That would look like (put it in the same file where you put the member_action)
filter :group, :as => :select, :collection => proc { Group.for_select }
The proc is there to make sure changes to groups (adding/removing/..) are immediately reflected to the select-list in the filter. That has to do with class caching in production.
Dont forget to put this scope in your Group model.
scope :for_select, :select => [:id, :name], :order => ['name asc']
Another way is to use scopes. If you have a field in your Group model, like a slug/label that could serve as a method header then you could do something like this in your activeadmin user register block:
Group.all.each do |group|
# note the sanitization of the Group name in the gsub
scope "#{group.name.gsub(/-/,'_')}".to_sym
end
And this in your User model:
Group.all.each do |group|
# note the sanitization of the Group name in the gsub
scope "#{group.name.gsub(/-/,'_')}".to_sym, joins(:group).where("group.name = ?",role.name)
# using joins(:group) or joins(:groups) makes a difference,
# so not sure as I have not tested, but maybe the where should be
# ....where("groups.name = ....
end
It should give you nice buttons above your index views like here: http://demo.activeadmin.info/admin/orders
If you want this for a has_and_belongs_to_many relation, I suggest you take a look at this Rails3 Active Admin - How to filter only records that meet all checked items in collection
Good luck!
I am designing a basic file manager (the Asset model) in the Active Admin gem. Each Asset HABTM Groups, and vice-versa.
In my active_admin Asset resource I have a filter where I want to be able to
select multiple groups to filter by, so I added:
filter :groups_id, :as => :check_boxes, :collection => proc {Group.all}
All of the groups show up as checkboxes as expected. However, if I have asset_1, asset_2 and I have group_1 assigned to asset_1 and asset_2, and group_2 to asset_2, when I
filter by both roles, asset_2 lists itself twice.
How can I restrict the filter to use only "distinct" or "unique" assets to be returned?
I also have another problem, which is that the filters are not working at all in any of my scopes.
A quick update on Will's answer. I'm running Rails 5.0 and ActiveAdmin 1.0, and clean_search_params returned an error. But this worked instead:
def apply_filtering(chain)
super
#search.result(distinct: true)
end
Thanks!
Active admin read indicates to add
distinct: true
to get unique results.
To apply that to active admin, I'm using doing that like this:
controller do
def apply_filtering(chain)
#search = chain.ransack clean_search_params params[:q]
#search.result(distinct: true)
end
end
has_and_belongs_to_many accepts a :uniq option which ensures that only uniq records will be returned. Setting this in your model should do the trick.
class MyModel
has_and_belongs_to_many :things, :uniq => true
end
... and, a quick addition Alex's answer:
If you want to do this for all controllers in your app, you can add this to an initializer (mine's called active_admin_patches.rb) -
# This guarantees that the results for a filtered #index page search do not appear more than once, on any #index page in the AA app
# TODO: THIS WILL PROBABLY FAIL WITH SOME FUTURE UPDATE, SO BE READY TO UPDATE IT FROM THE LATEST GEM SOURCE
module ActiveAdmin::ResourceController::DataAccess
# Applies any Ransack search methods to the currently scoped collection.
# Both `search` and `ransack` are provided, but we use `ransack` to prevent conflicts.
def apply_filtering(chain)
#search = chain.ransack(params[:q] || {})
# This is the original line
# #search.result
# This is the patch
#search.result(distinct: true)
end
end
I'm not sure why anybody wouldn't want this to be the default behavior, but there's probably a reason. Hmm, maybe for cases where a column of the index view is one of the non-distinct rows. Yeah, that must be it.
Also, there's bound to be a better way to patch this less intrusively, but I'm in a hurry. :-)
Two questions:
1) How can I make a column in the 'list' for a model consist of data from the record's association? In other words, I have a user model and a user has_many posts. I want to simply have a "post count" column in the list. I tried doing:
field :posts do
formatted_value do
value.count
end
end
but that results in a divide by zero error. I even tried doing:
field :posts do
formatted_value do
bindings[:object].posts.count
end
end
but got the same results.
2) How can I filter the listing to a particular scope? For example, I want to make the users post count be a link that is clickable which will show all posts for the given user.
The best I could figure out how to do this was to do:
# note that I created a method post_count to temporarily solve problem #1
field :post_count do
formatted_value do
bindings[:view].link_to value, "/admin/posts?query=#{bindings[:object].id}"
end
end
Which doesn't work very well. Is there a way to instruct rails-admin to do a .where(:user_id => xxx) on the model?
The other thing I wasn't crazy about was having to manually put in 'admin/posts'.. I was trying to see if I could do rails_admin_list_path(:model_name => "posts"). but that didn't seem to work.
You'd probably get a better response on the rails_admin mailing list - http://groups.google.com/group/rails_admin/
For your first question, this should do the trick:
field :posts, :virtual do
formatted_value do
bindings[:object].posts.count
end
end
For your second question, rails_admin now has a filter system - see the "add filter" dropdown at http://demo.railsadmin.org/admin/players . Tapping into that would be a much better method.
rails_admin_list_path(:model_name => "posts") should work, you might have to include Rails.application.routes.url_helpers or similar.
Try adding this to your rails_admin.rb
RailsAdmin.config {|c| c.label_methods << :field_name}
worked for me