I was just trying to use
self.name = 'Tom'
inside my user model but the column does not get updated.
Using
self.update_column(:name, 'Tom')
and
update_column(:name, 'Tom')
works.
Has the first way of changing value been deprecated?
self is an object, when you do self.name = 'Tom', it just sets the new value in attribute at object level, but to save it in the database, you need to call save method on self after setting the value.
self.name = 'Tom'
self.save!
Give it a try!
self.name = 'Tom'
Calls the setter method name= that ActiveRecord generates from your columns. This just updates the object in memory and marks the attribute as changed so when you call .save or .save! the changes are persisted to the database.
Has the first way of changing value been deprecated?
No. You just completely misunderstood what it does. Using the setters has never automatically caused a database update. That would be really unexpected behavior.
self.update_column(:name, 'Tom') and update_column(:name, 'Tom') are actually the exact same thing. The first just has an explicit recipient while the later is implicit. But in both cases the recipient is self. Like its big brother the #update method this creates a UPDATE sql query.
Related
So im using an api to get info on weather, its executes everyday, what im trying to do is to get updated if already exist, and create a new one if it doesn't in table.
I do want to update all attributs when udpdating.
i did try
model = Model.where(column_name: value).first_or_initialize(locked: false)
but i get an error saying :
unknown attribute locked for Model
raise UnknownAttributeError.new(self ,k.to_s)
If you need anything, ask and i will comment or edit. Im newb to ruby and rails
Firstly, the model.Model part should be just Model, as Model is your class.
locked is supposed to be a column/attribute of the Model class, although it seems is not the case judging from your error. Therefore, I'm gonna use other_column_name as an example.
Explanation of what this is doing:
Model.where(column_name: value).first_or_initialize(other_column_name: some_value)
Model.where(column_name: value): gets models that satisfy the condition column_name == value
first_or_initialize: if a model such that column_name == value was found, that one is returned. Otherwise, it initializes a model with column_name = value.
By passing other_column_name: some_value, if the model was not found and needs to be initialized, it sets other_column_name to some_value but: 1) it does not update it if it was initially found and 2) it does not save the record.
The equivalent of first_or_initialize that saves the new record would be first_or_create but this would still not update the record if it already existed.
So, you should do something like this:
m = Model.where(column_name: value).first_or_initialize
m.other_column_name = some_value
m.save
This way, you first get a model where column_name is value or initialize a new one with this value if it didn't already exist. Then, you set the attribute other_column_name to some_value and save the model.
A one-liner alternative would be
Model.where(column_name: value).first_or_create.update(other_column_name: some_value)
However, note that if it needs to be created, this one will perform 2 queries (the insert and the update).
About the error part. It says the attribute locked does not exist on the Model record. Are these classes you created? Are you using some pre-existing project? You could try posting Model.attribute_names and maybe your schema.rb
Firstly refer to the docs here
A table by the name of weather with the following attributes location: string temperature:integer wind:string needing to be updated or initialized based on the location would work like this
#weather_record = Weather.find_or_initialize_by(location: location_value)
#weather.temperature = -60
#weather.wind = strong
#weather.save
Next, never, ever use a reserved name for a model so do not have Model as the name of your table
Lastly in your example
model.Model.where(column_name: value).first_or_initialize(locked: false)
you are saying
a_record.ClassName.where which is just wrong, If you are using a class method then start with the class name e.g. Weather.where if you are using instance methods then use the instance name e.g. an_instance_of_weather.some_field
Try this mate:
column_name_value = (Way that you get the info from data)
model = Model.find_or_initialize_by column_name: column_name_value
Let me know if worked!
I have a database trigger that modifies a field on INSERT. Then when I run object.my_attribute it returns nil instead of lets say 42.
If I do object.reload.my_attribute, this is fine. But I don't want to reload the whole object or part of it unless it is necessary. And I believe code shouldn't be concerned when and how an object was created. It should just be correct.
Is it possible to mark that particular attribute as outdated and any attempt to get its value to result in a query that fetches it from database?
For example:
after_save :forget_my_attribute
def forget_my_attribute
forget_field :my_attribute
end
I think it's better to make some service object where field is modified and call it when create the record. CreateModel.call(args) instead of Model.create(args). It will be more clear than database trigger I think
But you can do something like this
after_create_commit :fetch_my_attribute
def fetch_my_attribute
self[:my_attribute] = self.class.find_by(id: id)[:my_attribute]
end
Or more flexible fetch attribute you need dynamically
def fetch_attribute(atr)
self[atr] = self.class.find_by(id: id)[atr]
end
object.fetch_attribute(:my_attribute)
I've got a query that does some math and returns a calculated custom select field with the result set. I cannot figure out how to access that in the activerecord object that is returned. I've added an attr_accessor for it also.
attr_accessor :percentage_used
select('gateways.*, (num_transactions_today/ SUM(num_transactions_today)) AS percentage_used ').joins(:gateway_groups).where('map_gateway_groups.gateway_group_id = ?', gateway_group_id)
in the result set, I would expect to have access to :percentage_used, but it is not in there. Any ideas on what i'm doing wrong? i've never needed to do this before.
Thanks
You can access it as
object["percentage_used"]
You neither need nor want attr_accessor for that. attr_accessor creates an instance variable, an accessor method for getting the value of that instance variable, and a mutator method for changing its value. When you say this:
select('gateways.*, (num_transactions_today/ SUM(num_transactions_today)) AS percentage_used ...
ActiveRecord will automatically add a percentage_used method to the returned objects. But the percentage_used method for accessing that value will be added by method_missing. Since you've said attr_accessor :percentage_used, method_missing will never be called and you can't get at the percentage_used value from the query in the usual way.
If you drop the attr_accessor :percentage_used, then you'll be able to call percentage_used on objects returned by that select and you'll find the values you're looking for. However, AR won't be able to convert the value to a native Ruby number though so you'll have to to_f the returned string yourself.
I want to access a newly created object inside of the conditional statement that created it:
if saved_object = Branch.new(params[:object]).save
puts saved_object.id
end
Activerecord instance save method always return true/false, so you need to initialize the object and check .save on it like below
saved_object = Branch.new(params[:object])
if saved_object.save
puts saved_object.id
end
As Naren Sisodya said, or you can use parentheses to disambiguate what is stored into saved_object (because right now saved_object holds the result of the .save call).
if (saved_object = Branch.new(params[:object])).save
puts saved_object.id
end
In this form, the saved_object variable will hold the database record and then .save will be called on that record. This is likely what you intended, but not what you got due to operator precedence rules in ruby.
I want to create a simple method for initializing different counter fields for users. However, I'm not sure how to set the value of a field referred to as a variable.
def self.initialize(user, field)
counter = "#{field}".to_sym
user.send(counter, nil)
user.save
end
I tried:
user.counter instead of user.send(counter), but it comes back with an undefined method error
user.send(counter) = nil, but that's not the correct syntax
Ruby's accessors work using the name= method for an attribute called name.
You can probably access it this way through the model attributes interface:
user[counter] = nil
user.save
Alternatively, a more generic way that should work on any Ruby object that exposes an attr_writer, attr_accessor, or equivalent:
user.send("#{counter}=", nil)
user.save
You'd only use the send version when dealing with arbitrary method names, like you have here. Converting to_sym is not strictly necessary.
Always be careful to white-list the kinds of method calls you're accepting. You shouldn't let counter be an arbitrary user parameter without some validation.