Scope all instances of an object with two depth relation - ruby-on-rails

Sorry for the title I have some difficulties to explain my issue, and even more in english.
My use case is that:
I have one user who has_many teams, each team own one game.
I would like add a method (a scope I believe) in my model user who gets me all the games who are related with the user. I thought something like that:
scope :games, includes({:teams => [:game]})
This line don't work for some reason i don't know yet.
But if I succeed to do that I will get all the teams and all the games.
Whereas I would like only an array with the games.
I search the more elegant way to do that.
Thanks for reading :)

If you use Rails 4, then all scopes must be wrapped in lambdas.
scope :games, -> { includes({:teams => [:game]}) }

Related

Why there is no easy way to unscope associations in rails (mongoid)?

I tried to google and read about it, but I could not find an easy solution or a very good answer in regard to this topic. There are many similar questions, solving people's problems. I could not figure out how to solve mine and on top of that I still wonder why nobody did not solve that yet. It is such a common problem I think.
I am using Rails 4 and Mongoid 4 with Mongoid Paranoia.
I want to implement a soft deletion for User. That works.
However I have an Event model which has_and_belongs_to_many :users, inverse_of: nil.
When I soft delete a user, who is a user of the event, then I seem to fail to find a way to have this user being fetched by default. Soft deleted users are not fetched, because of the default scope on User with deleted_at: nil.
Anyone enlightening out there ?
How to get started to implement something similar to what ActiveRecord offers:
has_and_belongs_to_many :users, -> { *a defined scope* }
I'm not sure if I am understanding you completely, but shouldn't calling another scope that utilizes unscoped do what you need. Docs here.
default_scope { where(deleted_at: nil) }
scope :some_other_scope, -> { unscoped.where(something_else: true) }
Edit
Ah, I see. Not the most elegant way but if you're set on not changing the default_scope of the User model; perhaps:
# Event model
def all_users
User.unscoped.where(event: self)
end

What are the drawbacks of a two-way polymorphic relationship in a Rail app?

I'm building a Rail 3.2 app that has some complex data relationships. I'm wondering what is the best way to structure the database.
The data I'm trying to model coud be compared to elements of Facebook.
For example, there are items that a user can create:
comments
photos
posts
status
updates
Each of these items can belong to a
user
business
location
So for example "User A took a photo at MacDonalds in Paris".
I want to show an activity stream on each user, business and location page.
The way I've thought of doing this involves a two way polymorphic relationship.
one for activity:
class ActivityFeed
belongs_to :feedable, :polymorphic => true
end
class Comment | Photo | Status
has_many :activity_feeds, :as => :feedable
end
and one for ownership
class ActivityOwner
belongs_to :ownable, :polymorphic => true
end
class User | Business | Location
has_many :activity_owners, :as => :ownable
end
Then activity_owner would belong to activity_feed, and activity_feed would have many activity_owners.
I hope that makes sense?
Is this a good way to tackle this case? Are there any performance issues I should be thinking about? Is there a better way?
A followup question: using this approach, is it possible to map the same model to a polymorphic relationship in multiple ways. For example a user could be an owner of a photo, and they could be a tagged user.
I'm stil trying to learn Rails, and I'm struggling to get my head around this issue. I'd really appreciate opinions, experience and ideas from others, as well as any pointers to useful information or guides.
Thanks!
http://blog.smartlogicsolutions.com/2008/06/13/ruby-on-rails-polymorphic-association-benchmarks/
it is old a little bit but still actuall
no big drawbacks if u r using right indexes, just less columns in your db
Interesting, Have a look at Polymorphic Association (revised) by Ryan Bates. I think it will be a perfect approach to what you are trying to do. Nice and clean too

What is scope/named_scope in rails?

I've recently started an internship. My employer uses ruby on rails, and I frequently encounter new syntax that I need to look up to understand. I've googled around for a good explanation of named_scope, but what I've found so far is mostly blog posts giving high praise for it, rather a straight definition or introduction.
What exactly is named_scope (now simply called scope) in ruby on rails?
A scope is a subset of a collection. Sounds complicated? It isn't. Imagine this:
You have Users. Now, some of those Users are subscribed to your newsletter. You marked those who receive a newsletter by adding a field to the Users Database (user.subscribed_to_newsletter = true). Naturally, you sometimes want to get those Users who are subscribed to your newsletter.
You could, of course, always do this:
User.where(subscribed_to_newsletter: true).each do #something
Instead of always writing this you could, however, do something like this.
#File: users.rb
class User < ActiveRecord::Base
scope :newsletter, where(subscribed_to_newsletter: true)
#yada yada
end
If you're using Rails 4 or newer, do this instead:
#File: users.rb
class User < ActiveRecord::Base
scope :newsletter, -> { where(subscribed_to_newsletter: true) }
#yada yada
end
This allows you to access your subscribers by simply doing this:
User.newsletter.each do #something
This is a very simple example but in general scopes can be very powerful tools to easy your work.
Check out this link: API Description
scope in active record is like class methods but they return Relation object which means you can call another scope or active record querying method on it.
For example, if you have a Zombie model (zombies table) with below mentioned scope methods,
class Zombie
scope :rotting, -> { where(rotting: true) }
scope :fresh, -> { where('age < ?', 25) }
scope :recent, -> { order(created_at: :desc) }
end
And you call
Zombie.rotting.fresh.recent.limit(3)
It translates to the below in SQL,
select "zombies.*" from "zombies" where "zombies"."rotting" = 't' and (age<20) order by create_at desc limit 3
Example above is based on rails 4 syntax
The best way to understand about the details is to go to API Documentation.
You'll get the complete details and the ways we can use Scopes.
API Documentation of Scope
Imagine you have a model: Person.
Now imagine you :
want all the people in the world who have red hair.
want all the people in the world who play cricket
You could get those particular classes of people by using a scope!
Person.red_hair.cricket ## finds all people with red hair who play cricket
Person.red_hair ## finds all people with red hair
Person.cricket ## finds all people who play cricket.
Now that wasn't so hard was it?

ActiveRecord and getting unused records from a relationship, find_by_sql or named_scope?

Some context:
I have some models that look like this
Actor has_many Acts
Act belongs_to Actor, belongs_to Decision
Decision has_many Acts, belongs_to Prompt
Prompt has_many Decisions
What I need to do is in the ActorsController, get a random Prompt that has not been used yet of all the available Prompts.
In my rails app, Actors are presented with prompts that give them a few choices to make. When they make a choice (Decision), that is saved in the db as an Act.
I've tried various iterations of named_scope and find_by_sql, but none worked, and I'm not even sure if my thinking was right to begin with on them, since there are so many models at work, and I don't seem to know where to start.
I hope this gives an idea of what I'm up against. I'd appreciate even a general pointer to form a plan of attack even.
Thanks!
edit
After chewing on this for a couple hours, I've got something working but it's very messy, and my logs are filled with SQL calls, so it could definitely stand a critical eye.
In the Prompt model:
named_scope :available, lambda { |used|
{ :conditions => ["id NOT IN (?)", used ] }
}
In the Actor model:
def used_prompts
prompts = Array.new
if self.acts && self.acts.length >= 1
self.acts self.acts.each { |act| prompts.insert(0, act.decision.prompt.id) }
return prompts.sort
else
return [0]
end
end
And in the ActorsController:
#prompt = Prompt.available(#actor.used_prompts).find(:first, :order => "RAND()")
Obviously the if block in used_prompts is one guilty party here, but I don't know a better way to deal with that since I can't do self.acts.decisions.each or some such thing. Maybe someone can school me :)
The simplest thing to do would be to add a after_create or similar callback on the Decision model that marks the associated prompt as used. You could also achieve this using some joins, but that would take a little more work, and will possibly lead to scalability issues (if you care).

Rails: the better app infrastructure

I'm trying to make a comment system, identical to the stackoverslow's one. There's a 1-st level comment, and a bunch of a second level comments, attached to it. The first straightforward idea that came up in order to do that, was to create a separate model, sub_comment. But I still got this feeling, that I should inherit the initial comment's properties, only adding a simple comment-id joint.
I'm still a Rails newbie, so the question is - can I do that? How? Is it a simple
class sub_comment < comment
model inheritance? But of course, I'm gonna need all the controller methods in order to add/delete these sub-comments. Or should I make a single comment model, where the 1-st level comment will have a nil as a parent?
What would be the right solution?
PS. Fell free to advice any book that covers the subject. I'm on a self education here, so I'd love to read everything that could clarify any future app architecture question.
I find it easier to have a simple tree structure with two pointers to make back-tracking easier:
class Post < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
acts_as_tree
belongs_to :post
named_scope :top_level, :conditions => { :parent_id => nil }
end
This makes it easy to retrieve all comments for a particular Post:
#comments = #post.comments.top_level
You can even pull up multiple levels of comments using AJAX or by fetching one layer after the next:
# Repeat while comments are found
loop do
level = #post.comments.find(:all, :conditions => { :parent_id => #comments.collect(&:id) })
if (level.empty?)
break
else
#comments += level
end
end
These can be sorted as required for presentation purposes.
One option is to have two separate classes, and put the shared behavior in a module. That way you're not doing Single Table Inheritance (which is what your inheritance example would mean, and it's something I have had problems with) but you also aren't duplicating code.
Conceptually, you're trying to create a self referencing association. This is certainly the cleanest way to go as you don't have extra tables and models to worry about, though it can be complex to setup.
I'd recommend checking out the Self Referential Association Railscast, it will walk you step by step how to get started.
The short and sweet answer is that I would go with your "parent id is nil" methodology for top-level comments and clearly sub comments would have parent id's. Remember, DRY rules the day in the Rails world. If you can use one class (in this case it makes sense), you should.

Resources