1

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

CodrinM
  • 139
  • 1
  • 9
  • Just no `locked` attribute for your `Model` :) – mechnicov Apr 05 '22 at 22:13
  • 1
    @mechnicov could you explain a little bit, i still dont really know what locked: false does. But if i eliminate locked: false from that line its just create news and not updating already existing ones. And if i put trtue, getts same erros as false – CodrinM Apr 05 '22 at 22:14
  • When you call [`first_or_initialize`](https://apidock.com/rails/ActiveRecord/Relation/first_or_initialize) you need to pass model attributes as arguments – mechnicov Apr 05 '22 at 22:27
  • 1
    Does this answer your question? [Upsert in Rails ActiveRecord](https://stackoverflow.com/questions/4695563/upsert-in-rails-activerecord) – mechnicov Apr 05 '22 at 22:32
  • i did see there is that upsert method, but im newb in rais and ruby, and i cant get to understand how to use it, could you give an exemple if you know ? – CodrinM Apr 05 '22 at 22:58
  • 1
    Please post your models fields – jamesc Apr 06 '22 at 06:44
  • Could you maybe post the result of running this on rails console? `Model.attribute_names` – raquelhortab Apr 06 '22 at 08:07

3 Answers3

1

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

jamesc
  • 12,423
  • 15
  • 74
  • 113
1

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

raquelhortab
  • 430
  • 4
  • 13
  • `locked` is not valid attribute for this model. Please look error message above. Also we don't know rails version, `update_attributes` is deprecated in new versions – mechnicov Apr 06 '22 at 09:41
  • @mechnicov Read the last paragraph. I already mentioned the error part in the answer, but I can't know more unless the OP posts the model's atrributes. What I did is to explain what the code did and how to do what was asked (create or update if the record exists). From there, if they post more details, I can help more. You are right about `update_attributes` – raquelhortab Apr 06 '22 at 14:01
  • Code in your answer will raise error, so it's not relevant – mechnicov Apr 06 '22 at 14:10
  • @mechnicov, so explaining what their code does and how to achieve what they ask with the little available infro is irrelevant?? I think it was pretty clear in the answer that locked didn't seem to be a correct attribute but I edited it so it is even more clear. As said, we could help more if we had more info but I believe this answer can make the OP understand the code, this makes it somehow relevant to me. – raquelhortab Apr 07 '22 at 13:58
  • 1
    Now after editing the message, it has become clearer `d( ̄◇ ̄)b` – mechnicov Apr 07 '22 at 14:07
1

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!

Yung Sifilis
  • 120
  • 10