check out the acts as voteable plugin on github, looks like you've already
got your modeling done correctly to just drop it in.

-C
2009/11/8 J. Pablo Fernández <[email protected]>

> Hello Railists,
>
> I have a piece of Ruby on Rails code that has a complex SQL query (well,
> not that complex, but as far as I know beyond the ORM capabilities) and for
> my taste it has too many strings and harcoded values. I'd like to improve it
> as much as possible, so my question is open ended, what else can I do to
> improve it?
>
> Some particular issues I have
>
> - Is there a way to get a table name to use it in a query in the same
> escaped way as the ORM does? I think this is database independent,
> being `items` for MySQL but not for other databases.
> - In the same vein, is there a way to get a field name the same way Rail's
> ORM would put it in a SQL query?
> - Maybe there's a way to get both, the table name and the field name in one
> operation. I'm imaging something like Item.voteable_id.for_query
> => "`items`.`voteable`".
> - How do I escape code to avoid SQL injection when not in conditions? I'm
> using the user_id variable directly in a query and although it's impossible
> for a user to put anything in it, I'd rather escape it properly. In a
> condition I would do ['user_id = ?', user_id], but in a join or a select,
> how do I do it?
> - Does my use of class constants here make sense?
> - Is there any chance at all of using the ORM and less string?
> - Any other thing to do to it?
>
> The code is this one
>
> class Item < ActiveRecord::Base
>   has_many :votes, :as => :voteable
>
>   def self.ranking(user_id)
>     Item.find(:all,
>       # items.* for all the Item attributes, score being the sum of votes,
> user_vote is the vote of user_id (0 if no vote) and voter_id is just user_id
> for latter reference.
>       :select => "items.*,
>                   IFNULL(sum(all_votes.value), 0) as score,
>                   user_votes.value as user_vote,
>                   \"#{user_id}\" as voter_id",
>       # The first join gets all the votes for a single item (to be summed
> latter).
>       # The second join gets the vote for a single user for a single item.
>       :joins => ["LEFT JOIN votes as all_votes ON
>                     all_votes.voteable_id = items.id and
>                     all_votes.voteable_type = \"Item\"",
>                  "LEFT JOIN votes as user_votes ON
>                     user_votes.voteable_id = items.id and
>                     user_votes.user_id = \"#{user_id}\" and
>                     user_votes.voteable_type = \"Item\""
>                 ],
>       :group => :id,
>       :order => "score DESC")
>
>     # This is the query it should generate
>     # SELECT items.*, user_votes.value as user_vote, sum(all_votes.value)
> as score
>     # FROM items
>     # LEFT JOIN votes as all_votes ON
>     #     all_votes.voteable_id = items.id and
>     #     all_votes.voteable_type = "Item"
>     # LEFT JOIN votes as user_votes ON
>     #     user_votes.voteable_id = items.id and
>     #     user_votes.user_id = 2 and
>     #     user_votes.voteable_type = "Item"
>     # GROUP BY items.id
>     # ORDER BY score DESC
>   end
>
>   def score
>     s = read_attribute("score")
>     if s == nil
>       votes.sum :value
>     else
>       Integer(s)
>     end
>   end
>
>   def user_vote(user_id)
>     if Integer(read_attribute("voter_id")) == user_id
>       Integer(read_attribute("user_vote"))
>     else
>       vote = votes.find(:first, :conditions => ["user_id = ?", user_id])
>       if vote
>         vote.value
>       else
>         0
>       end
>     end
>   end
> end
>
> Thanks.
> --
> J. Pablo Fernández <[email protected]> (http://pupeno.com)
>
> >
>

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Ruby 
on Rails: Talk" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/rubyonrails-talk?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to