19

In my Rails 4 app Project (model) has_many Videos (model). I have a named scope in the videos model:

scope :live, where( is_deleted: 0, sent_to_api: 1 )

In one of my project views, I do this (project is an instance of Project):

project.videos.live.size

What I expect to get is the number of projects in that specific project but instead I get the number of videos in any project. It's as if .live is not returning a subset from .videos but rather replacing it.

I see it explained here that chaining named scopes with one another should be combined with logical AND but when applied to an "association method" [<--not sure the proper terminology for .videos in this context] that doesn't seem to be happening.

What's the right way to do this?

Community
  • 1
  • 1
emersonthis
  • 32,822
  • 59
  • 210
  • 375

2 Answers2

26

I believe it should read like this in Rails 4:

scope :live, -> { where(is_deleted: 0, sent_to_api: 1) }

The rails 4 docs and all examples in it show you passing in a callable object to the scope to ensure it gets called each time. If it doesn't work like this try implementing it as a class method and see how that works out for you.

http://api.rubyonrails.org/classes/ActiveRecord/Scoping/Named/ClassMethods.html

Mike Waldrup
  • 757
  • 6
  • 11
  • 2
    I'm new to Ruby/Rails and I haven't seen that `->` syntax before. Is it standard Ruby or something added by Rails? – emersonthis Sep 13 '13 at 18:36
  • My (limited) understanding is that it's new with Rails 4. I remember scopes from my Rails 3 projects that certainly didn't require to pass in the object like that. My assumption is also supported by the Rails 3 guides here: http://guides.rubyonrails.org/v3.2.13/active_record_querying.html#scopes which don't show objects being passed to any of the scopes, so that about assures it for me. – Mike Waldrup Sep 13 '13 at 18:43
  • 1
    You're definitely right that it's a Rails 4 thing because I see a deprication warning in the log when I write a scope without it. But my follow-up question was actually just about the `->` operator its self. I've not seen it before and I just want to understand what it is. – emersonthis Sep 13 '13 at 18:51
  • 11
    @Emerson - The `->` is syntax for a "Stabby Lambda". Shorthand for a traditional lambda block. – veritas1 Sep 13 '13 at 19:24
  • @veritas1 Thanks!! I suspected it was something like that. – emersonthis Sep 13 '13 at 19:37
  • @Emerson Side note on this, default_scope can just be passed a block, no proc object required (although it will work that way as well). – Mike Waldrup Sep 14 '13 at 01:11
  • @MikeWaldrup Just default_scope or any named scope? I'm more comfortable with blocks, so that's good to know. – emersonthis Sep 14 '13 at 04:58
  • @Emerson Docs show just default_scope with that option. Not exactly sure why though. – Mike Waldrup Sep 14 '13 at 16:19
3

I would just go for class methods and leave scopes behind. The syntax is much simpler because it's just like any other class method, including passing parameters to it.

Try:

def self.live
  where( is_deleted: 0, sent_to_api: 1 )
end

And then:

project.videos.live.size

and see if it helps.

For more info, read here.

mjnissim
  • 3,102
  • 1
  • 19
  • 22
  • Just to note.. scopes and class methods behave differently – bullfrog Apr 16 '14 at 05:29
  • 5
    the linked article is out of date. the author edited it saying that the bug mentioned was fixed, and he uses scopes for simple things. From the rails docs 4.1 "This (scope) is exactly the same as defining a class method, and which you use is a matter of personal preference" – hajpoj Jun 13 '14 at 17:40