Rails 3 delete all elements of an array - ruby-on-rails-3

I am trying to delete an array of users but the way I have it it is deleting one by one. Is there a better way to do it?
My code is:
#users ||= User.where("clicks_given - clicks_received < ?", -5).to_a
#users.each do |user|
user.destroy
end

You can just use Rails' built-in methods. Note that you need to wrap your query in an array (if you're interpolating variables) when using these methods.
To iterate over each one calling destroy (which will run callbacks, etc.):
User.destroy_all(["clicks_given - clicks_received < ?", -5])
Or to just delete these in the database in a single query (no iteration over each item), you can do this, but keep in mind it won't run your callbacks:
User.delete_all(["clicks_given - clicks_received < ?", -5])

You could use the destroy_all method:
User.destroy_all("clicks_given - clicks_received < ?", -5)
Reference: http://apidock.com/rails/v3.0.5/ActiveRecord/Relation/destroy_all
I've also used the following before:
#users.map(&:destroy)
It's essentially doing the same thing as your each call, but you can avoid the boiler-plate code.

Related

How to prevent using a named_scope from creating n+1 queries

What is the best way to prevent ActiveRecord from making an unnecessary query when referencing a list of models that already been loaded?
class Checklist
has_many :checklist_items
scope :active, where(active: true)
end
class ChecklistItem
belongs_to :checklist
scope :active, where(active: true)
end
#checklists = Checklist.active.includes(:checklist_items).where(checklist_items: {active: true})
# Works fine, does NOT make extra SQL query
#checklists[0].checklist_items
# Makes extra query. How do I prevent this?
#checklists[0].checklist_items.active
What is the best work around for preventing this extra query when using a named_scope?
As soon as you use where, you'll trigger another query. If you think you have all your records in memory, treat the resulting active record relation as an array, not SQL. Use array methods like select instead of where. Perhaps:
#checklists[0].checklist_items.select {|ci| ci.active == true}

Create scopes using instance methods best way

I was wondering what's the best way to make an scope using an instance method to filter records. This is my model:
class Promotion < ActiveRecord::Base
scope :availables, lambda{ all.select{ |obj| obj.is_available? } }
def is_available?
Date.today <= Date.strptime(valid_thru, '%m/%d/%Y')
...more validations here
end
end
The problem here is this scope returns an array instead of an ActiveRecord::Relation and I'm not able to chain other scopes.
Any suggestion guys?
There is no way to accomplish what you want. If you want to apply logic on ruby objects you can no longer return an ActiveRecord::Relation.
The only way to achieve something like this is have the logic on a database level. In that case you could use a class method to achieve what you want like so:
def availables
where('valid_thru => ?', Date.today)
end

Find_by_sql and calculated field

I am using find my sql, and I want to calculate something in the database and add to my model.
I wil try to simplify the code
class User < ActiveRecord::Base
attr_accessor :comments_count
end
And somewhere else:
#users = User.find_by_sql("select * (select count(*) from comments where user_id=u.id) as comments_count from Users u")
#user.map{|u| puts u.comments_count}
Any help?
ActiveRecord will, unfortunately, not just match any selected columns to attributes on the model. However, something like that would probably be fairly easy to put together. First you'd need to overload find_by_sql to something like this -
def self.find_by_sql(sql)
values = connection.select_all(sql)
objects = []
values.each do |row|
objects << self.new(row)
end
objects
end
Then the initialize function for your model can mass assign the schema-based attributes, and then handle assigning your custom attributes. Its not as clean or simple a solution as you were probably hoping for, but it should accomplish the task. And you could probably write the initialize function so that it is fairly generic, in that it can mass assign all the schema-based attributes, and then match leftover keys that were passed in with any attributes that may be present on self.
Ok, i got it.
It has nothing to do with attr_accessor. I had to remove it.
#users = User.find_by_sql("select * (select count(*) from comments where user_id=u.id) as comments_count from Users u")
#user.map do |u|
puts u.comments_count if #user.has_attribute?(:comments_count)
end

named_scope and .first?

I can return a collection of objects, with only one (:limit => 1) but is there a way to return the .first() object only, like not within a collection?
named_scope :profile, :conditions => {:association => 'owner', :resource_type => 'Profile'}, :limit => 1 # => collection of 1 profile but I want the profile only NOT in a collection or array
the workaround is simply to apply .first() to the results, but I'd just like to clean up the code and make it less error prone.
You'll probably need to create a class method instead:
def self.profile
where(:association => 'owner', :resource_type => 'Profile').first
end
Note that with Rails 3 you should be using the where(...) syntax, and that when doing .first, you don't need to specify the limit.
First off, if you're using Rails 3 you should be using scope instead of named_scope. Same thing, different, err, name (named_scope will still work, but it is deprecated). Now that that is out of the way…
A scope (or named scope) takes two arguments (a symbol and either a lambda or a hash) and defines a class method on that model that returns an ActiveRecord::Relation, which is why you're able to chain methods on it.
first, like find or all, returns an actual result from the database. For this reason it won't work in a scope.
All that said, you can define your own class method on your model that gives the behavior you're wanting (as 2 people already answered while I was typing this). This is actually recommended over using scopes by many well-respected devs in the Rails community. Since using the scope class macro just defines class methods itself anyways, there isn't really a downside to this, and it has the benefit of flexibility (like in your case here).
Define a class method to do this:
def profile
where(:association => "owner", :resource_type => 'Profile').first
end
The first already does an implicit limit 1 on the query, AND will order it by the primary key of the table so you'll always get the first.

rails 3: difference between write_attribute and update_attribute

I did not know about write_attribute until today...
it seems like update_attribute, although not calling validation is still calling the :before_save callbacks, whereas write_attribute doesn't.
Is that the difference between these two methods?
update_attribute actually makes a physical call to the DB. You get a full execution of an UPDATE statement. It's like update_attributes but just for a single column.
While write_attribute writes the attribute for assignment to the model for AR based columns. If you were to overwrite a DB based attribute.
def first_name=(val)
write_attribute :first_name, val
end
# some_model.first_name => 'whatever val is'
def first_name=(val)
#first_name = val
end
# some_model.first_name => nil
I have not looked into write_attribute extensively, but I gather Activerecord based models handle assignments to db based columns slightly differently than your run of the mill accessor.
write_attribute is used when you want to overwrite the default accessors for a method. It is essentially syntactic sugar for self[:attribute]=(value).
Have a look at the ActiveRecord::Base documentationunder the heading "Overwriting default accessors".
If you tried to rewrite the example in the documentation using update_attribute, I'd imagine it would end up in a loop.