How was ActiveRecord "none" method implemented with NullRelation? - ruby-on-rails

I am trying to understand the none method introduced in Rails4.
Here is the implementation from Rails API
def none
where("1=0").extending!(NullRelation)
end
And I found similar implementation here in Rails3 way.
scope :none, where(:id => nil).where("id IS NOT ?", nil)
Can anyone help me understand how this method was implemented with NullRelation in Rails4 and advantages?

Let's first check ActiveRecord::NullRelation
They basically set to constant values all methods, so whatever you are going to use, won't hit the database.
Remember that when you chain methods over a relation you get a new relation every time, which means, once you hit none, all future methods will try to build a relation from that one. It's easy to imagine that they won't find anything in the database and will just keep returning self (the NullRelation).
In addition, considering that you already linked the current implementation, is pretty clear that they will keep returning an ActiveRecord::Relation, but obviously it won't find anything due to the '1=0' approach. The key point however is in the extending! method, which will overwrite the methods for ActiveRecord::Relation instance (not for all relations, so that's like a singleton instance in Ruby) by forcing it not to hit the database (the exec_queries is replaced with a simple empty array as return value).

Related

Handling associations w/ null objects in Rails

I'm using the Null Object pattern in my Rails application to implement the concept of a guest user account.
Like many apps, I have a method on ApplicationController called current_user.
In the case of a non-logged in user, I want to use my guest user null object.
It works in many cases, but then there run into something like the following -
params.merge({ user: current_user })
MyModel.new(params)
Of course this fails, with the following exception.
ActiveRecord::AssociationTypeMismatch: User expected, got GuestUser
My question is, what is a way to elegantly handle this kind of case. The idea for the Null Object pattern is that you can transparently swap in this null object and have it essentially be a duck type of the real object.
It's obvious how to do that for methods being called on the object, but in this case, I want to be able to pass this in and basically have it set the association column to null, rather than needing a whole bunch of custom logic (avoiding that is the whole point of the null object pattern anyway).
A polymorphic relation isn't quite it.
Quick answer: No such thing as an elegant way to handle that (I'm not sure how elegance is quantified).
You'll have to create a concern that mimics the persistence methods of the model from which your null object is based on (User). You'll also have to write methods to appease ActiveRecord to make the associated column be nil.
Fortunately for you, this use-case has been solved
if your MyModel accepts null for user_id, then you can do
params.merge(user: current_user) unless current_user.is_a?(GuestUser)
MyModel.new(params)
Using the null object pattern here is definatly not a good idea since you need database generated ids to build associations and maintain referential integrity if you intend the user to have any kind of persistence before "registering".
Allowing a MyModel to be created without a user_id would essentially create an orphaned record and just gives you another problem of linking it to user behind the screen. Thats why your schema should not allow it in the first place.
Rather you want to create the guest user record when needed (like when a guest user adds the first item to a cart) and use a recurring task (like a Cron tab) to periodicaly clean out junk records.
I would also consider if you really want to setup guest users as a seperate class since STI and polymorphism tends to get really messy when joining. Just use a timestamp column (records when the account was activated) or an enum instead.
One option would be to override the user= method, so that it's aware of the existence of GuestUser (and can handle appropriately):
def user=(value)
if value.is_a?(GuestUser)
super(nil)
else
super
end
end
All mass-assignment methods in Rails (create, update, etc.) will use the appropriate setter to set the value. This can be easily be put into a concern if this is a common pattern in your application.
If you don't allow nil in the user_id column you have the flexibility to do something like assign a sentinel value, which you could then use in your accessor as well:
def user
if user_id == GUEST_USER_ID
GuestUser.new
else
super
end
end
I had a similar problem. I just went from assigning the object to assigning the object.id which I set to nil on the Null Object. It is kind of a hack I think though.

Rails, activerecord: self[:attribute] vs self.attribute

When accessing active record column/attributes in rails, what is the difference between using self[:attribute] vs self.attribute? Does this affect getters and setters?
They're both just methods to get to the attribute - they're both just getters. self.attribtue is a more "traditional" getter, whereas self[:attribute] is basically just the [] method. Switching between using either has no ramifications.
I'd recommend using only the self.attribute method because it's syntactically nicer. However, using the self[:attribute] can come in handy when something else overrides the self.attribute method.
For example, suppose you have a User model with a name database column, so you'd get user.name. But let's say you install a gem that adds a #name method to each of your models. To avoid the complication, one option is to use user[:name] to access it directly without going through the compromised method.
There's a key difference that the accepted answer misses. If you are attempting to modify the attribute while setting the value, then you must use self[:attribute].
For example...
def some_attr=(val)
self.some_attr = val.downcase # winds up calling itself
end
This won't work, because it's self-referencing (you'll get a "Stack too deep"
error). Instead you must assign the value by doing...
def some_attr=(val)
self[:some_attr] = val.downcase
end
There's also a named method write_attribute, which performs the same action as self[:attribute]. Both do what you need, it's a matter of coding style and personal preference. I like write_attribute when the attribute I'm actually defining is variable, e.g.
write_attribute(var, 'some value')

Prevent sql update on existing Rails model when appending to has_many relationship

According to the present Rails documentation, regarding the << operator on a has_many relationship on an existing object:
collection<<(object, …)
Adds one or more objects to the collection by setting their foreign keys
to the collection’s primary key.
(This is the interesting bit)
Note that this operation instantly fires update sql without waiting for
the save or update call on the parent object.
I didn't realize this would happen, I was quite surprised; I could have sworn this was not the case in the past, though I admit I could be wrong.
In either case, I haven't been able to find any additional documentation regarding this, however I wonder if there is a way to prevent this update?
My situation is simple, I merely have an object which exists in the database, which is being prepared for an "edit" page. I append one or multiple related objects before the page is render. C'est tout.
Update:
Apparently the same update-scenario also occurs if you set the has_many relationship directly from an array using the = operator.
Use the collection's build method. That won't immediately fire a SQL statement like the others do.
foo.bars.build(attributes)
foo.save
Lots of good information can be found here: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
Note: This method assumes you have the flexibility to create your objects through the build method rather than using Bar.new.

cant understand meaning of following lines in haml file

#{#current_user.allowed_events.size}
#{#current_user.batch_mates.size}
link_to "<span>#{#current_user.related_colleges.size}</span>Colleges".html_safe
in above lines what are these allowed_events.size,related_colleges.size?
are these builtin functions?
Most likely allowed_events and batch_mates are either an association or method on the User model (assuming that's what #current_user references). Take a look in apps/models/user.rb and see if you find anything there.
Those methods are likely returning an ActiveRecord::Relation which is sort like a class wrapper around an array of models, typically returned from a database search. Anyway, the ActiveRecord::Relation class has a size method which is very similar to length or count.
So it's most likely just spitting out the number of allowed events and batch mates that belong to the current user.
As for the #{} that's just triggering Ruby interpolation. You could also do it this way:
= #current_user.allowed_events.size
= #current_user.batch_mates.size
As per the code, current_user is an object of User model. related_colleges and allowed_events could be associations/method/name scope in use model, you need to see your User.rb file in model to get it. I think these are associations (likely has_many) where size is the method to get the count of associated objects

problem using sql instead of named scope in rails

I have a method "search" in my model, which depending upon the various parameters passed runs an sql query in which i am joining seven tables. but when i am using this method with another named scope then error is shown "undefined method call for array".
but when instead of this search method if i use group of named scope then it works fine.
so how to integrate named scope with that method
It's a little hard to tell for sure without seeing the code. But it sounds like the search method is intended to be called on the Model class and when you chain the named_scope calls either they don't know what to do with the array your search method supplies or your search method doesn't know what to do with the array of records the names scope supplies.
I think your #search method is probably returning something (an Array?) that does not implement some method that named_scope expects. From a quick look into activerecord/lib/active_record/named_scope.rb it appears that named_scope returns a Scope object, which does implement #call (and a bunch of other non-Array methods too). That looks to be why chaining scopes works. So an Array just isn't going to work.
Could you rework your #search method into a named_scope? I realise that you're going to get an unusually (for me, at least) complex definition, but you should then be able to chain your results with other scopes.
Alternatively, how about making your custom search method work so that it returns (and must also take, for chaining before and after to work) a Scope? Probably haarder to do than a big named_scope though.
hey sorry for replying late, but found the answer
I have stored the query in a variable and then passed to the named scope where i do find_by_sql.
hence got the desired result.

Resources