ActiveAdmin: sort by child association's property - ruby-on-rails-3

I am having these objects:
class District < ActiveRecord::Base
belongs_to :city
end
class City < ActiveRecord::Base
has_many :districts
end
What I would like to do (and been unable to do so thus far), is: have a City column in District's index and that column should be sortable on City.name.
Closest thing I was able to do without crashing ActiveAdmin is:
index do
column City.human_name(:count => :other), :city, :sortable => :city_id
end
Which of course is not good enough; I don't want to sort on foreign key's integer value.
Tried stuff like :sortable => 'city.name', gives an error. Even tried to do it like you do it on "pure" Rails - :joins => :cities, :sortable => 'city.name' - no luck. Tried a bunch of other stupid stuff, got annoyed and decided to humbly ask for help.
Can anyone point me in the right direction?
Thanks for your time.

That should also do the work:
index do
column City.model_name.human, :city, :sortable => 'cities.name'
end
controller do
def scoped_collection
end_of_association_chain.includes(:city)
end
end

Try this.. It will help....
index do
column :city, :sortable => :"cities.name" do |district|
district.city.human_name(:count => :other) if district.city.present?
end
end
controller do
def scoped_collection
District.includes(:city)
end
end

Very simple and readable solution:
index do
column :city, sortable: "cities.name"
end
controller do
def scoped_collection
# join cities
super.includes :city
end
end

Use the name of the table, probably cities. It might look like this:
District.joins(:city).order("cities.name")

Related

sunspot surely this can be done with some ruby magic?

I need to access my rails model instance from inside the searchable block as indicated below.
class Product
include MongoMapper::Document
include Sunspot::Rails::Searchable
key :field_names, Array
searchable do |ss|
self.field_names.each do |field|
ss.double field[:name] do
field[:value]
end
end
end
end
does anyone know how to do this via Sunspot ?
I have a field_names array on each product instance that is different per product so i need to access it.
Thanks a lot
Rick
you mean this?
def Foo
attr_accessible :id, :title
def fields
['something']
end
searchable do
integer :id
string :title
string :fields, :multiple => true do
self.fields
end
end
end
well inside there, you're inside a different evaluation context (Solr::DSL or something like that). That's to provide the ability to have those keywords like "integer, string". Looks like you're trying to evaluate dynamic attributes/filters .. .. so see my modified response (below)
you mean this?
def Foo
attr_accessible :id, :title
#fields_to_dynamically_add = ['title']
searchable do |s|
s.integer :id
s.string :title
#fields_to_dynamically_add.each do |f|
s.string f.to_sym
end
end
end
PS: have not added fields to searchable blocks dynamically every myself (although the above works)

Group By multiple column for sql count statement , in rails environment

I have two Relations (class)
class RecommendedForType < ActiveRecord::Base
attr_accessible :description, :name
has_many :recommended_for_type_restaurants
end
And
class RecommendedForTypeRestaurant < ActiveRecord::Base
attr_accessible :recommended_for_type_id, :restaurant_id, :user_id
belongs_to :restaurant
belongs_to :user
belongs_to :recommended_for_type
def self.get_count(rest_id)
r = RecommendedForTypeRestaurant.where(restaurant_id: rest_id)
#result = r.includes(:recommended_for_type)
.select("recommended_for_type_id, recommended_for_types.name")
.group ("recommended_tor_type_id, recommended_for_types.name")
.count
end
end
if I call
RecommendedForTypeRestaurant.get_count(1) # get stat of restaurant_id: 1
I get
{"dinner"=>1, "fast food"=>1, "lunch"=>3, "romantic dinner"=>1}
My goal is to get both id and name of RecommendTypeFor in the return result as well. currently i can only make it return either id or name. Something like this
{{"id" => 1, "name" => "dinner", "count" => 1}, {"id" =>2, "name" => "lunch", "count" => 3} }
For sure i can do another round of sql once i get id or name to create that hash but i think that not the efficient way. Appreciate any help or suggestion :)
You need to group separately, try the following group.
.group ("recommended_tor_type_id", "recommended_for_types.name").count
I believe that if you remove the .count at the end and change the select to:
.select("count(*), recommended_for_type_id, recommended_for_types.name")
You will get an array of models that will have the attributes you need and the count.
You should be able to test it out in the console by do something like this:
r = RecommendedForTypeRestaurant.where(restaurant_id: rest_id)
#result = r.includes(:recommended_for_type)
.select("recommended_for_type_id, recommended_for_types.name, count(*)")
.group ("recommended_tor_type_id, recommended_for_types.name")
#result.each do |r|
puts r.recommended_for_type_id
puts r.name
puts r.count
end
Hope it helps!

Rails: changing from three columns in a table to one

I am modifying a Documents table from using three columns (article1, article2, and article3) to one (articles) which has a string of comma-separated IDs stored in it (i.e., 23,4,33,2). That's all working well, but I'm trying to adjust the functions that read the three columns to read the one and I'm getting rather stuck.
In the model I have:
scope :all_articles, lambda {|p| where(:page => p) }
In the controller I have this:
#articles = (1..3).to_a.map { |i| Article.all_articles(i).reverse }
And in the view:
<% #articles.each_with_index do |a, i| %>
<%= a[i].name %>
<% end %>
It's just a bit beyond me at this point.
Cheers!
It's usually not good practice to put store the ids in a column like you have done. It is better to break that relationship out into a Has and Belongs to Many relationship. You set it up in your models like this:
class Document < ActiveRecord::Base
#...
has_and_belongs_to_many :articles
#...
end
class Article < ActiveRecord::Base
#...
has_and_belongs_to_many :documents
end
Then you will create a join table that ActiveRecord will use to store the relationships.
create_table :articles_documents, :id => false do |t|
t.integer :article_id
t.integer :document_id
end
add_index :articles_documents, [:article_id, :document_id], unique: true
This will allow you to query a lot more efficiently than you are currently doing. For example, to find all documents that have some article id. You would do:
#documents = Document.joins(:articles).where("articles.id = ?", some_article_id)
Or if you want to query for a document and return the articles with it:
#documents = Document.includes(:articles).where(some_conditions)

Elasticsearch: filtering by group with tire gem

I want to filtering search by age groups.
Now I have:
program.rb
class Program < ActiveRecord::Base
has_many :age_groups, through: :programs_age_groups_relations
include Tire::Model::Search
include Tire::Model::Callbacks
mapping do
indexes :name, analyzer: 'snowball', boost: 100
indexes :description, analyzer: 'snowball'
indexes :age_groups do
indexes :name, analyzer: 'snowball'
end
end
def to_indexed_json
to_json(include: {age_groups: {only: :name}})
end
def self.search(params, options={})
tire.search(load: {include: 'age_groups'}) do
query do
boolean do
must { string params[:name_query] } if params[:name_query].present?
end
end
filter do
boolean do
if params[:age_groups].present?
params[:age_groups].each do |ag_name|
must { string ag_name }
end
end
end
end
end
end
index.html.haml
= form_tag programs_path, method: :get do |f|
= text_field_tag :name_query, params[:name_query]
- AgeGroup.all.each do |ag|
= check_box_tag 'age_groups[]', ag.name, params[:age_groups].include?(ag.name)
in controller:
#programs = Program.search(params)
Age Groups:
AgeGroup.create([{name: 'Baby'}, {name: 'Toddler'}, {name: 'Preschoolers'}, {name: 'Elementary'}, {name: 'Middle School'}])
Realtion:
class ProgramsAgeGroupsRelation < ActiveRecord::Base
attr_accessible :age_group_id, :program_id
belongs_to :age_group
belongs_to :program
end
When I check one or more age_groups in search form nothing was happened with search result.
How can I correctly use tire for this task?
I'm not sure I understand your question, but please check this StackOverflow answer: Elasticsearch, Tire, and Nested queries / associations with ActiveRecord for info on ActiveRecord associations with Tire.
Once you have that sorted out, please update your question, as “nothing was happened with search result” hints at some kind of failed expectation, but I don't know which one.

Rails 3: Find parent of polymorphic model in controller?

I'm trying to find an elegant (standard) way to pass the parent of a polymorphic model on to the view. For example:
class Picture < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true
end
class Employee < ActiveRecord::Base
has_many :pictures, :as => :imageable
end
class Product < ActiveRecord::Base
has_many :pictures, :as => :imageable
end
The following way (find_imageable) works, but it seems "hackish".
#PictureController (updated to include full listing)
class PictureController < ApplicationController
#/employees/:id/picture/new
#/products/:id/picture/new
def new
#picture = imageable.pictures.new
respond_with [imageable, #picture]
end
private
def imageable
#imageable ||= find_imageable
end
def find_imageable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
end
Is there a better way?
EDIT
I'm doing a new action. The path takes the form of parent_model/:id/picture/new and params include the parent id (employee_id or product_id).
I'm not sure exactly what you're trying to do but if you're trying to find the object that 'owns' the picture you should be able to use the imageable_type field to get the class name. You don't even need a helper method for this, just
def show
#picture = Picture.find(params[:id])
#parent = #picture.imagable
#=> so on and so forth
end
Update
For an index action you could do
def index
#pictures = Picture.includes(:imagable).all
end
That will instantiate all 'imagables' for you.
Update II: The Wrath of Poly
For your new method you could just pass the id to your constructor, but if you want to instantiate the parent you could get it from the url like
def parent
#parent ||= %w(employee product).find {|p| request.path.split('/').include? p }
end
def parent_class
parent.classify.constantize
end
def imageable
#imageable ||= parent_class.find(params["#{parent}_id"])
end
You could of course define a constant in your controller that contained the possible parents and use that instead of listing them in the method explicitly. Using the request path object feels a little more 'Rails-y' to me.
I just ran into this same problem.
The way I 'sort of' solved it is defining a find_parent method in each model with polymorphic associations.
class Polymorphic1 < ActiveRecord::Base
belongs_to :parent1, :polymorphic => true
def find_parent
self.parent1
end
end
class Polymorphic2 < ActiveRecord::Base
belongs_to :parent2, :polymorphic => true
def find_parent
self.parent2
end
end
Unfortunately, I can not think of a better way. Hope this helps a bit for you.
This is the way I did it for multiple nested resources, where the last param is the polymorphic model we are dealing with: (only slightly different from your own)
def find_noteable
#possibilities = []
params.each do |name, value|
if name =~ /(.+)_id$/
#possibilities.push $1.classify.constantize.find(value)
end
end
return #possibilities.last
end
Then in the view, something like this:
<% # Don't think this was needed: #possibilities << picture %>
<%= link_to polymorphic_path(#possibilities.map {|p| p}) do %>
The reason for returning the last of that array is to allow finding the child/poly records in question i.e. #employee.pictures or #product.pictures