with_scope should not be protected.

I recently upgraded my edge rails in order to take advantage of the view_paths patch Rick applied the other day, and discovered with_scope is now protected. I'm well aware of the abuses of with_scope, but isn't this approach sort of heavy-handed? Since when has Rails been about protecting programmers from themselves?

If core needed with_scope to implement assocations doesn't it stand to reason that a Rails developer might need similar functionality? Let me give you my use case:

class User < ActiveRecord::Base   def accessible_property_find(*args)     Property.with_scope(:find => accessible_property_options) do       Property.find(*args)     end   end end

A couple of things to note here:

* I'm not using this in a controller in a mysterious way, it's in a model as it should be, but the protected method is still inaccessible since I'm calling it from a different model. * An association doesn't do the trick here, the actual conditions vary depending on user type and aren't a simple foreign key. * I know I could work around this by refactoring the functionality into Property and passing the user as a parameter, but that makes my code both more complicated and more opaque. The User should know what properties it can access. A Property shouldn't have any concept of the user.

So I'm requesting that this change be rolled back. Thoughts?

Since, um … forever?

Well why isn't it written in Java then?

You can always access it via send():

   Foo.send(:with_scope, ...) do      # ...    end

All that making it protected does is make sure people realize they
are taking their lives into their own hands when they play with it in
scopes where they shouldn't be playing with it.

- Jamis

+1 to rolling back this change until there's a way to make with_scope available to association extensions.

The useful (and AFAIK popular) technique for creating typed join models detailed at has_many :through - New on edge: Magic join model creation is broken by making with_scope protected.

There were many fights about with_scope back when it was public. Rails is opinionated, and it is the opinion of the core team that it should become protected to ensure clean MVC. When you think about it, it makes sense. You can still leverage with_scope in your public model methods that accept a block.

There were also people that wanted to be able to access sessions and controller params in their models. Naturally, the core team wouldn’t allow that. Imagine what would happen if they did…

Oh … now I see buggy GMail keeps me out of sync, and that you’re discussing association extensions and model-to-model stuff. My bad, sorry - I will show myself out.

Come on now, that's a totally bogus analogy. The separation between M and VC is huge. You gain so incredibly much from having your models independent that there's absolutely no reason to support that.

The whole with_scope thing is much more nuanced. Please review my use case and tell me how it should be done. If you saw my whole architecture, you would see that giving Property any knowledge of User to work around this would just be ugly. Sending the method to Property is definitely the best solution unless there is some other avenue I haven't thought of.

I just get this feeling that there's been this huge crackdown due to misuse without looking at the actual use cases where it might be justified.

Oh ... now I see buggy GMail keeps me out of sync, and that you're discussing association extensions and model-to-model stuff. My bad, sorry - I will show myself out.

Don't feel bad.. GMail got me too just now. :frowning:

class User < ActiveRecord::Base   def accessible_property_find(*args)     Property.with_scope(:find => accessible_property_options) do       Property.find(*args)     end   end end

NFI what accessible_property_options is, but I'm guessing it has to do with the current user? This is closer to how I'd approach the problem:

class Property < AR::Base   def find_with_user(user, *args)     with_user(user) { find *args }   end

  protected   def with_user(user, &block)     with_scope :find => user.accessible_property_options, &block   end end

class User < AR::Base   def accessible_property_find(*args)     Property.with_user(*args)   end end

The Property store should be the one responsible for scoping its own data retrieval. If the User needs to specify conditions then it shouldn't be done w/o the Property datastore's knowledge (with_scope), it should tell the Property data store the conditions it wants applied, and the Property store can use whatever it needs to make that happen (in this case an AR with_scope). See Rick's example for a better separation of responsibilities.

-- tim

I see what you're saying, but I think it's a little presumptuous to dictate this architecture just to satisfy an abstract concept of how things should be structured. David often says how he hates contrived examples, and removing with_scope access to other models feels like it's based on certain assumptions that don't always hold. Here's why:

* The first thing is that ideally this would be modelled by User has_many :accessible_properties, but that is not possible because accessible_properties does not have static conditions (they depend on the instance, therefore they can't hardcoded with a class macro... if there is a way around this please do tell). An association proxies to another model without requiring extra hooks to be defined on the target model. I want to do the exact same thing because: * The notion of accessible properties is mostly meaningful to the user. I think if you saw my entire app, you would see my point of view. I have a pretty clean division of concerns where the User model is in charge of policing its own access to things, while the other models just remain focused on their own data. I realize this is sort of a 6-of-one-half-a-dozen-of-the-other aesthetic issue, but: * If I decide the only meaningful interface is through User, why should I have to have twice the methods and add a layer of indirection where with_scope is specifically designed for this situation? Rails does place high value on aesthetics after all.

In short, I'm not trying to make a nuisance of myself on an old issue. When I heard with_scope would be protected it didn't bother me because I just assumed it would work in all models, but I didn't realize it would mean you could only scope within the same model. Given the limitations of associations, I think that's an undue restriction.

First thing:

class << ActiveRecord::Base   public :with_scope end

Second thing:

* The first thing is that ideally this would be modelled by User has_many :accessible_properties, but that is not possible because accessible_properties does not have static conditions (they depend on the instance, therefore they can't hardcoded with a class macro... if there is a way around this please do tell).

You can do this. If you pass in a conditions string between single quotes, it will be interpolated by your instance. That is:

has_many :accessible_properties,   :class_name => 'Property',   :conditions => 'face_id = #{id}'

#{id} will be the id of your object, not your class. Dynamic.

Brilliant. Okay, my grievances are really starting to melt away now.