rails build or update method? - ruby-on-rails

I'm currently using the find or create method to update an associated record which i use to store cached information, but I'm wondering if there's some simpler alternative method similar to build since the object is a has_one relation. The problem with just using build_ is in most cases the object will exist and needs to be updated. I could use a bunch of ifs the check but wondered if there was some better rails-fu than I'm using currently.
def self.update_caches(data)
cache = SpaceCache.find_or_create_by_space_id(#space.id)
cache.rating = ((data.ratings.sum / data.ratings.size)/20).round
cache.price_min = #space.availables.recent.average(:minimum)
cache.price_avg = #space.availables.recent.average(:price)
cache.save
end
Bonus:
I also read here:
http://m.onkey.org/active-record-query-interface
That the rails calculation methods average, sum, etc will be depreciated in 3.1, so should I'm unsure if I should be replacing them?
count(column, options)
average(column, options)
minimum(column, options)
maximum(column, options)
sum(column, options)
calculate(operation, column, options)

I wrote one for my has_one :event.
def build_or_update_event(params)
result = new_record? ? build_event(params) : event.update_attributes(params)
result != false
end

Related

Result check with activerecord

When we are checking one active record result is empty or not, what will be
way which have more performance.
pc_count = Property.select("id").where('property_category_id = ?', 5).limit(1)
if pc_count.blank?
#
end
if pc_count[0]
#
end
In two ways i have tried this pc_count.blank? or pc_count[0], because i heard that blank will take extra query, but when i tried that in console i couldn't see that any extra call
Try exists
which will be like.
Person.exists?(5)
Person.exists?('5')
Person.exists?(:name => "David")
Person.exists?(['name LIKE ?', "%#{query}%"])
Person.exists?
refer: http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-exists-3F
No, both your versions do not produce another query.
It depends what you are doing with pc_count:
1.) You are using that id somewhere later, then use either of your methods (i prefer .blank?)
2.) You only need this for the this check. Then I would do
Property.select("id").where('property_category_id = ?', 5).limit(1).count
because there will be no model created and you can just test count == 0

Rails common method for updating a database field

I am new to rails and I have a task to write a common method that will update a specific database field with a given value. And I should be able to invoke the method from anywhere in the app.(I understand about the security flaw and so on.. But I was asked to do it anyway) In my application controller I tried
def update_my_model_status(model,id,field, value)
#model = model.find(id)
#model.update(field: value)
end
Of course this doesn't work.. How to achieve this? What is the right way to do this? And if it is possible how to pass a model as an argument to a method?
If you're using Rails, why not use Rails?
Compare update_all:
MyModel.where(id: 1).update_all(banned: true)
or maybe update_attribute:
my_model.update_attribute(:banned, true)
to:
update_my_model_status(MyModel, 1, :banned, true)
Notice how, despite being shorter, the first two approaches are significantly more expressive than the last - it is much more obvious what is happening. Not only that, but they are immediately more familiar to any Rails developer off the street, while the custom one has a learning curve. This, combined with the added code from the unnecessary method adds to the maintenance cost of the application. Additionally, the Rails methods are well tested and documented - are you planning to write that, too? Finally, the Rails methods are better thought out - for example, your prototype naively uses attribute validations, but does not check them (which could result in unexpected behavior) and makes more SQL queries than it needs to. It's fine to write custom methods, but let's not write arbitrary wrappers around perfectly fine Rails methods...
Try this:
def update_my_model_status(model,id,field, value)
#model_var = model.capitalize.constantize.find(id)
#model_var.update_attributes(field: value)
end
Instead of just using update you should use update_attributes:
def update_my_model_status(model,id,field, value)
#model_var = model.find(id)
#model.update_attributes(field: value)
end
http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update

Using Rails update_all method to update fields with value from another column

I'm trying to update a field in using update_all. However I need the value to be taken from another field which is re-written to my specific format.
If I have something like this in my model:
def self.clean_mac_address()
clean_mac_address = :macaddress.gsub(/[^0-9a-z]/i, '')
end
When I run this:
Radacct.update_all("mac_clean = #{clean_mac_address}")
I get an error:
NoMethodError: undefined method `gsub' for :macaddress:Symbol
Any thoughts how I can do this? Or is there a simpler way to update the field?
update_all generates a single SQL query to run - it can't do clever stuff like change arbitrary bits of ruby into equivalent SQL.
You either need to load all you instances (via find_each for example) and fix them one by one (ie don't use update_all), for example
Foo.find_each do |foo|
# update foo here
foo.save!
end
Or find a way of expressing that cleaning operation in SQL. For example Postgres has a regexp_replace function
Foo.update_all("some_column = regexp_replace(some_column, 'your_regexp_here', '','g')")
Which would remove everything replacing that regexp. Obviously you'll need to check the documentation for your database to see whether it supports such a feature.
While the accepted answer provides a nice way to update_all, what I'd use is
read_with_clean_addr = Radacct.where(mac_clean: :macaddress.gsub(/[^0-9a-z]/i, ''))
read_with_clean_add.update_all(mac_clean: "#{clean_mac_address}")

Is the Active Record Base update method deprecated?

I'm trying to update many active records at the same time using the :update method and they don't seem to update fine.
#drop_ship_order_line_items = DropShipOrderLineItem.update(params[:drop_ship_order_line_items].keys, params[:drop_ship_order_line_items].values).reject { |dsoli| dsoli.errors.empty? }
params[:drop_ship_order_line_items] returns the following hash:
{"11"=>{"available"=>"1"}, "2"=>{"available"=>"1"}}
But the models don't seem to update correctly...anyone with insides?
AFAIK you can't update models like this on rails, you would have to do it like this:
params[:drop_ship_order_line_items].each do |key,value|
DropShipOrderLineItem.find( key ).update_attributes( value )
end
EDIT
There's probably an attr_protected call somewhere in your code, you should check which attributes are protected or not in there.
If you think you can safely ignore the protection on this specific call, you can use some sending do work out the magic (disclaimer: this is on your own, i'm just showing a possibility):
params[:drop_ship_order_line_items].each do |key,value|
ship = DropShipOrderLineItem.find( key )
value.each do |property,value|
ship.send( "#{property}=", value )
end
ship.save
end
This is going to overcome the attribute protection, but you should make sure this is a safe call and you're not going to burn yourself by doing this.

How to store different site parameters in database with Rails?

There are a lot of ways to store site preferences in database. But what if I need to manage datatypes. So some preferences will be boolean, others strings, others integers.
How can I organize such store?
I wrote a gem that does exactly this, and recently updated it for Rails 3:
For Rails 3:
http://github.com/paulca/configurable_engine
For Rails 2.3.x
http://github.com/paulca/behavior
Enjoy!
I am quite lazy with preferences and store the data as serialized JSON or YAML Hashes. Works really well, and generally preserves the data types as well.
I used a single table with a single row, and each column representing one preference. This makes it possible to have different datatypes.
To be able to retrieve a preference, I overrode method_missing to be able to retrieve the preference value directly from the class name without requiring an instance, something like this:
class Setting < ActiveRecord::Base
##instance = self.first
def self.instance
##instance
end
def self.method_missing(method, *args)
option = method.to_s
if option.include? '='
var_name = option.gsub('=', '')
value = args.first
##instance[var_name] = value
else
##instance[option]
end
end
end
Thus, to retrive a setting, you would use:
a_setting = Setting.column_name
Rails Migrations are used to create and update the database.
http://guides.rubyonrails.org/migrations.html

Resources