trying to walk a tree, always getting no results - ruby-on-rails

I have a n-tier affiliate system which I'm trying to walk so I can get counts and lists of affiliates' sub-affiliates. I have, among other fields, an "id" and "affiliate_id" on each entry.
def find_affiliates_under(affid)
affs=Array.new
Affiliate.find(:all, :conditions => "affiliate_id = " + affid.to_s, :select => :id).each do |a|
affs.concat(find_affiliates_under(a.id))
end
return affs.uniq
end
What am I doing wrong? Would appreciate a pointer from someone with more experience with Ruby
Thanks!

Are you the id's or are you also looking for the nested objects themselves. By placing a select => :id option, you're only going to select the id of each object.
May I recommend taking a look at awesome_nested_set. I think it will achieve what you're trying to do, while saving you some time.

Related

Datamapper: Sorting results through association

I'm working on a Rails 3.2 app that uses Datamapper as its ORM. I'm looking for a way to sort a result set by an attribute of the associated model. Specifically I have the following models:
class Vehicle
include DataMapper::Resource
belongs_to :user
end
class User
include DataMapper::Resource
has n, :vehicles
end
Now I want to be able to query the vehicles and sort them by the name of the driver. I tried the following but neither seems to work with Datamapper:
> Vehicle.all( :order => 'users.name' )
ArgumentError: +options[:order]+ entry "users.name" does not map to a property in Vehicle
> Vehicle.all( :order => { :users => 'name' } )
ArgumentError: +options[:order]+ entry [:users, "name"] of an unsupported object Array
Right now I'm using Ruby to sort the result set post-query but obviously that's not helping performance any, also it stops me from further chaining on other scopes.
I spent some more time digging around and finally turned up an old blog which has a solution to this problem. It involves manually building the ordering query in DataMapper.
From: http://rhnh.net/2010/12/01/ordering-by-a-field-in-a-join-model-with-datamapper
def self.ordered_by_vehicle_name direction = :asc
order = DataMapper::Query::Direction.new(vehicle.name, direction)
query = all.query
query.instance_variable_set("#order", [order])
query.instance_variable_set("#links", [relationships['vehicle'].inverse])
all(query)
end
This will let you order by association and still chain on other scopes, e.g.:
User.ordered_by_vehicle_name(:desc).all( :name => 'foo' )
It's a bit hacky but it does what I wanted it to do at least ;)
Note: I'm not familiar with DataMapper and my answer might not be within the standards and recommendations of using DataMapper, but it should hopefully give you the result you're looking for.
I've been looking through various Google searches and the DataMapper documentation and I haven't found a way to "order by assocation attribute". The only solution I have thought of is "raw" SQL.
The query would look like this.
SELECT vehicles.* FROM vehicles
LEFT JOIN users ON vehicles.user_id = users.id
ORDER BY users.name
Unfortunately, from my understanding, when you directly query the database you won't get the Vehicle object, but the data from the database.
From the documentation: http://datamapper.org/docs/find.html. It's near the bottom titled "Talking directly to your data-store"
Note that this will not return Zoo objects, rather the raw data straight from the database
Vehicle.joins(:user).order('users.name').all
or in Rails 2.3,
Vehicle.all(:joins => "inner join users on vehicles.user_id = user.id", :order => 'users.name')

can rails active-record's methods accept a parameter in an array format?

I have a model 'Car'. Its structure looks like this.
Car
=========
Make:string
Year:integer
Before, I learned that some methods in ruby, especially active record's, actually take an array as parameter.
Then, instead of finding a collection in traditional way:
Car.find(:all, :limit => 10, :offset => 5)
Can I perform searching the collection like this?
Car.find([:all, {:limit => 10, :offset => 5}])
I have tried above in the console, but it didn't work for me.
I'm just curious to know why it didn't work the way it was supposed to be.
any advice would be really appreciated.
You can not pass the argument like array, its predefined for ids. like:
Car.find([1,2,3,4,5])
Have a look on link :
http://apidock.com/rails/ActiveRecord/Base/find/class

Getting the id with a rails find with :select

I have this rails find that i need to get the id as well but if i put the id in the :select wont it effect the query and is there another way to get the id
#past_requests = Request.find_all_by_artist(name, :conditions => ["showdate < ?", Time.now], :select => "distinct venue, showdate")
#past_requests = Request.find_all_by_artist(name, :group => "venue, showdate")
code long for view. i'm remove your condition. sorry about this. Hope it'll helpful for you. :)
To be fair in cases where distinct returns a single row out of maybe 5 duplicates who's to say which id out of those 5 should be displayed in your result? I'm afraid what you are asking for is not practical. Maybe you misunderstand what distinct is used for ? Give us more info pls.

Finding a specified taggable_type with acts-as-taggable-on

So in another controller, I use a find like this:
#entries = Entry.find(:all, :conditions => ['live = ?', false])
to find all the entries with a false 'live' column.
In my project I'm using two different taggable types, one for entries (Entry), and one for messages (Message). After looking at my tried and true code above you would think that I could do something similar to find all the tagged messages with the "Message" value in the taggable_type column of the taggings table.
#this could help find only Messages with the taggable_type column value "Message"
#tagged_messages = Message.find(:all, :conditions => ['taggable_type = Message', true])
The problem here is that my find condition addresses the Message model [Message.find(...] Which won't work because [from my understanding] the taggings table doesn't have an associated model. I'm probably wrong. So how do I search a table that's not associated with a model? I'm probably completely missing something here. I would greatly appreciate any help or code that would help me understand this or help get this working. Thanks for reading my question.
#tagged_messages = Tagging.find_all_by_taggable_type('Message').map(&:taggable) should do what you want. You might need to throw a uniq in there somewhere as well.

Better Performance on Associations

Right now I have a table called Campaigns that has many Hits, if I call say:
Campaign.find(30).hits
Which takes 4 seconds, or 4213 ms.
If I call this instead:
campaign = Campaign.find(30)
campaign.hits.count
Does it still load all of the hits, then count? Or does it see I am counting and avoids loading all of the hits? (Which is currently 300,000+ rows).
I am trying to figure out a smart way to load/count my hits. I am thinking about adding a method to my Campaign.rb model, like:
def self.total_hits
find :first, :select => 'COUNT(id) as hits', :conditions => ["campaign_id = ?", self.id]
end
I know that query won't load from the hits table, but that is just an example of counting it from a self made query, apposed to Ruby on Rails doing this for me.
Would this memcache query be more effecient? (I have it running, but doesn't seem to be any better/faster/slower, just the same speed.)
def self.hits
Rails.cache.fetch("Campaign_Hits_#{self.campaign_id}", :expires_in => 40) {
find(:first, :select => 'COUNT(id) as hits', :conditions => ["campaign_id = ?", self.campaign_id]).hits
}
end
Any suggestions would be great!
How about:
Campaign.find(30).hits.count
You might also consider adding the following in hit.rb (assuming a one-to-many relationship between campaigns and hits).
belongs_to :campaign, :counter_cache => true
You then need a column in the campaigns table called hits_count. This will avoid hitting hits altogether if you're only getting the count.
You can check the API for the full rundown.
My ActiveRecord might be a little rusty, so forgive me if so, but IIRC Campaign.find(30).hits is at least two separate queries. How does Campaign.find(30, :include => [ :hits ]).hits do? That should perform a single query.

Resources