group_by using value from other model - ruby-on-rails

Using ROR 2.3.8
I have this in cities_controller.rb:
#shops = Shop.published.search params[:keyword], {
:conditions => conditions,
:star => true,
:group_by => 'city_id',
:group_function => :attr,
:page => params[:page]
}.merge(:order => 'rating_average DESC')
#cities = #shops.collect { |shop| shopy.city }
How can I tell Rails to get the rating_average from City model instead of Shop model? Because the Shop model does not have rating_average. It's actually City model that gets rated.
Thank you.
UPDATES
published namescope in Shop.rb
sphinx_scope(:published) {
{:conditions => {:status => 'published'}}
}
Indexes in Shop.rb
define_index do
indexes city.name, :as => :name, :sortable => true
indexes city.duration, :as => :duration
indexes city.status, :as => :status
#has city.budget, :as => :budget
#has city(:created_at), :as => :created_at
has city(:rating_average), :as => :rating_average
has city_id
end
UPDATES 2
class City < ActiveRecord::Base
has_many :shops, :dependent => :destroy
...
end

You should use joins to acheive this:
#shops = Shop.published.search params[:keyword], {
:conditions => conditions,
:star => true,
:group_by => :city_id,
:group_function => :attr,
:page => params[:page]
}.merge(:order => :rating_average,
:sort_mode => :desc)
You should also add cities. or shops. before columns to specify which table's column.

Related

Rails thinking sphinx includes not working

I have the code like following
Listing.search(
Riddle::Query.escape(params[:search]),
:include => params[:include],
:page => page,
:per_page => per_page,
:star => true,
:with => with,
:with_all => with_all,
:order => params[:sort]
)
params[:include] contains the value like [:listing_images, :author, :category, :origin_loc]
I don’t know what was wrong here.

Rails 4 render json nested objects

I need to render as Json a complex structure. I have next structure working:
render :json => #booking, :include => [:paypal,
:boat_people,
:boat => {:only => :boat_model, :include => {:boat_model => {:only => :name, :include => { :boat_type => {:only => :name}}}}}]
but I´m not able to add a port attribute with some other nested attributes to :boat, such as :boat_model (at same level).
UPDATE:
Although it´s not working, I include my port attribute.
render :json => #booking, :include => [:paypal,
:boat_people,
:boat => {:only => [:boat_model => {:include => {:boat_model => {:only => :name, :include => { :boat_type => {:only => :name}}}}},
:port => {:include => :city => {:only => name}}]}]
I mean, boat_model and port are both boat attributes.
This is the model object:
class Boat < ActiveRecord::Base
attr_accessor :price
#price
attr_accessor :extrasPrice
#extrasPrice
def as_json(options = { })
h = super(options)
h[:price] = #price
h[:extrasPrice] = #extrasPrice
h
end
belongs_to :boat_model
belongs_to :port
belongs_to :state
has_many :photos
end
I got it.
render :json => #booking, :include => [:paypal,
:boat_people,
:boat => {:only => :name, :include => {:port => {:only => :name, :include => {:city => {:only => :name, :include => {:country => {:only => :name}}}}},
:boat_model => {:only => :name, :include => {:boat_type => {:only => :name}}}}}]
You are probably going to want a much more robust system for displaying JSON. The built-in Rails helpers are really designed primarily for simple additions that enable users to do most of what they would want to accomplish. However, in your case, you are trying to make it do more than it was designed for.
I would highly recommend either creating a view object or using a gem like RABL.
My preference is to use Rabl for complex JSON. It basically creates the 'view object' for you by building a domain specific language that makes it relatively easy to build complex JSON objects in rails.
RABL basically allows you to build views that format JSON instead of HTML. The DSL is extremely rich and enables you to do just about anything you would want. In your case, I think the code would look something like this:
app/views/bookings/show.rabl
object #booking
#these are attributes that exist on your booking model:
attributes :booking_attribute, :other_booking_attribute
child :paypal do
#these are attributes that exist on your paypal model:
attributes :paypay_attribute1, :other_paypal_attribute
end
child :boat_people do
#boat_people attributes that you want to include
attributes :blah_blah
end
child :boat do
#boat attributes that you want to include
attributes :boat_attribute1, :boat_attribute2
child :boat_model do
attributes :name
child :boat_type do
attributes :name
end
end
end

Ruby on Rails as_json limit

I have this "as_json" method in my Post model:
def as_json(options={})
super(options.merge(:include => { :comments => { :include => [:user] }, :hashtags => {}, :user => {}, :group => {} }))
end
I'd like to set a limit attribute in :comments like this:
def as_json(options={})
super(options.merge(:include => { :comments => { :include => [:user], :limit => 10 }, :hashtags => {}, :user => {}, :group => {} }))
end
but it doesn't work.
How should I proceed?
I think that you have only one possibility.
I suppouse that you have a has_many :comments association in your Post model
So you can define the next has_many association in your Post model, something like this:
has_many :ten_comments, -> { limit(10) }, class_name: "Comment", foreign_key: :post_id
And then you will be able to do this in the as_json method:
def as_json(options={})
super(options.merge(:include => { :ten_comments => { :include => [:user] }, :hashtags => {}, :user => {}, :group => {} }))
end
Sorry for posting four years later, but I hope that someone find useful your question and this answer.

How do I make a grouped select box grouped by a column for a given model in Formtastic for Rails?

In my Rails project I'm using Formtastic to manage my forms. I have a model, Tags, with a column, "group". The group column is just a simple hardcoded way to organize my tags. I will post my Tag model class so you can see how it's organized
class Tag < ActiveRecord::Base
class Group
BRAND = 1
SEASON = 2
OCCASION = 3
CONDITION = 4
SUBCATEGORY = 5
end
has_many :taggings, :dependent => :destroy
has_many :plaggs, :through => :taggings
has_many :monitorings, :as => :monitorizable
validates_presence_of :name, :group
validates_uniqueness_of :name, :case_sensitive => false
def self.brands(options = {})
self.all({ :conditions => { :group => Group::BRAND } }.merge(options))
end
def self.seasons(options = {})
self.all({ :conditions => { :group => Group::SEASON } }.merge(options))
end
def self.occasions(options = {})
self.all({ :conditions => { :group => Group::OCCASION } }.merge(options))
end
def self.conditions(options = {})
self.all({ :conditions => { :group => Group::CONDITION } }.merge(options))
end
def self.subcategories(options = {})
self.all({ :conditions => { :group => Group::SUBCATEGORY } }.merge(options))
end
def self.non_brands(options = {})
self.all({ :conditions => [ "`group` != ? AND `group` != ?", Tag::Group::SUBCATEGORY, Tag::Group::BRAND] }.merge(options))
end
end
My goal is to use Formtastic to provide a grouped multiselect box, grouped by the column, "group" with the tags that are returned from the non_brands method. I have tried the following:
= f.input :tags, :required => false, :as => :select, :input_html => { :multiple => true }, :collection => tags, :selected => sel_tags, :group_by => :group, :prompt => false
But I receive the following error:
(undefined method `klass' for
nil:NilClass)
Any ideas where I'm going wrong?
Thanks for looking :]
I'm not sure we support :group_by with a custom :collection. In fact, that who part of the code was a messy contribution. So, try omitting the :collection for starters, and see where you end up. If there's a bug with Formtastic, please add an issue on Github.
I'd first move your Group class out of this file, and just inherit from where you want, or use a Module in this class. This is the preferred way of getting methods an constants into a class and staying organized.

Thinking Sphinx and acts_as_taggable_on plugin

I installed Sphinx and Thinking Sphinx for ruby on rails 2.3.2.
When I search without conditions search works ok. Now, what I'd like to do is filter by tags, so, as I'm using the acts_as_taggable_on plugin, my Announcement model looks like this:
class Announcement < ActiveRecord::Base
acts_as_taggable_on :tags,:category
define_index do
indexes title, :as => :title, :sortable => true
indexes description, :as => :description, :sortable => true
indexes tags.name, :as => :tags
indexes category.name, :as => :category
has category(:id), :as => :category_ids
has tags(:id), :as => :tag_ids
end
For some reason, when I run the following command, it will bring just one announcement, that has nothing to do with what I expect. I've got many announcements, so I expected a lot of results instead.
Announcement.search params[:announcement][:search].to_s, :with => {:tag_ids => 1}, :page => params[:page], :per_page => 10
I guess something is wrong, and it's not searching correctly.
Can anyone give my a clue of what's going on?
Thanks,
Brian
Thinking Sphinx relies on associations in model. In common situations you only have to put index definition below your associations.
With acts_as_taggable_on plug-in you don't have tag-related associations in model file and when you write
indexes tags.name, :as => :tags
TS interprets it like:
CAST(`announcements`.`name` AS CHAR) AS `tags`
(look at sql_query in development.sphinx.conf, in my case).
I suppose that you have attribute name in model Announcement and don't run into error when rebuild index.
But we expect:
CAST(GROUP_CONCAT(DISTINCT IFNULL(`tags`.`name`, '0') SEPARATOR ' ') AS CHAR) AS `tags`
and:
LEFT OUTER JOIN `taggings` ON (`announcements`.`id` = `taggings`.`taggable_id`)
LEFT OUTER JOIN `tags` ON (`tags`.`id` = `taggings`.`tag_id`) AND taggings.taggable_type = 'Announcement'
To get things working just add tag-related associations in your model before you rebuild index:
class Announcement < ActiveRecord::Base
acts_as_taggable_on :tags,:category
has_many :taggings, :as => :taggable, :dependent => :destroy, :include => :tag, :class_name => "ActsAsTaggableOn::Tagging",
:conditions => "taggings.taggable_type = 'Announcement'"
#for context-dependent tags:
has_many :category_tags, :through => :taggings, :source => :tag, :class_name => "ActsAsTaggableOn::Tag",
:conditions => "taggings.context = 'categories'"
In define_index method:
indexes category_tags(:name), :as => :tags
has category_tags(:id), :as => :tag_ids, :facet => true
In controller:
#announcement_facets = Announcement.facets params[:search], :with => {:tag_ids => [...]}
#announcements = #announcement_facets.for.paginate( :page => params[:page], :per_page => 10 )
I found that simply defining the index thus:
Class Thing < ActiveRecord::Base
acts_as_taggable
define_index do
..other indexing...
indexes taggings.tag.name, :as => :tags
end
end
worked fine.
One possibility is that you need to declare the type for tag_ids as :multi because TS can get confused (I just discovered this here http://groups.google.com/group/thinking-sphinx/browse_thread/thread/9bd4572398f35712/14d4c1503f5959a9?lnk=gst&q=yanowitz#14d4c1503f5959a9).
But why not use the tag names to search? E.g.,
Announcement.search params[:announcement][:search].to_s, :conditions => {:tags => "my_tag"}, :page => params[:page], :per_page => 10
Or, if you need to search for multiple tags:
Announcement.search( "#{params[:announcement][:search].to_s} (#tags my_tag | #tags your_tag)", :page => params[:page], :per_page => 10 )
(as aside, you may want to sanitize/remove sphinx-control-characters from the user-provided query before using it).
For debugging, I would go into console and strip down your query as much as possible (eliminate pagination arguments, even the query (just do ""), etc.).

Resources