Can't add session variable - ActiveModel::MissingAttributeError - ruby-on-rails

I am not very confident with Rails but have recently started adding custom session variables in order to store some data such as id's. I am trying to set a call id to a recently created value but keep getting an error.
Code:
callid = Call.createCall(sessionid,tp_cd)
session[:callid] = callid
This exact same thing works in other actions in the same controller, but here I get:
ActiveModel::MissingAttributeError (can't write unknown attribute `callid`)
I am simply calling this action with a POST call in order to manipulate some data and set this session variable to be used later. There must be something fundamental that I am missing about how session variables work. Is there anything obvious that could cause this error?

It gives an error because Rails looks for a model called Session, not the session object that is part of the request cycle.
You can get the session like this
request.session[:callid] = callid

In rails, creating a new record on the model name is just create method.
callid = Call.createCall(sessionid,tp_cd)
so it should be like this:
callid= call.create(params)
in params you need to define it like this: column name : your variable/value. So what columns are in your Call model? if you have session_id column, it will be like this:
callid= call.create(session_id: value_given )

Related

Updating if exist or create if not rails

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!

Force TypeORM Enity.create to create one single instance of object

I am new to typeORM and I am making a basic CRUD API using the Active-record pattern.
I have a very basic entity and to save it to the database I use the following code:
const newUser = User.create(request.body)
But when I try to compile, User.create returns an User[] object instead of User.
If I call manually the method using the object, like User.create({username: request.body.username, ... }) I get successully an User, but when I use request.body I always get an User[] regardless if I use the exact same object as the body of my request.
I checked the documentation and User.create in fact has a override that returns a single User, if an object-like parameter is passed, but produces a User[] if an array-like parameter is passed.
I've tried many thigs, like destructuring User.create({... request.body}) and similar, but it does not work.
I think this is very confusing and prone to error, as User.create will behave differently using objects and the bodys request.
Does something like User.createOne() or something like that exist? so I can force the behavior to always create one single object?
I've not found anything.
You can force it by casting the request body to an object first
const newUser = User.create(request.body) // User[]
const newUser = User.create(request.body as Object) // User

Storing instance of a Class in a Rails session causes TypeError exception

In our Rails application we want to store an instance of a class in a session. This is because we want to set the class with some parameters when the user first logs into the application and then re-use this class by pulling it back out of the same session. When their session expires or they log out, this instance of the class is destroyed.
We're doing this to avoid using a Singleton class because that would live at Application-level and be available on different processes and stick around longer than the user's session, and have security implications due to it also being available to other users who haven't created a session yet.
So this is how it works:
session[:example_class] = ExampleClass.new(field_one: 'field_one', field_two: 'field_two')
This works fine!
However if I then do this:
current_instance = session[:example_class]
current_instance.do_something
session[:example_class] = current_instance
Whereby I am calling a method on this instance or whatever and then want to push that updated instance back into the session again so it's stored somewhere... we get this error:
TypeError in HomeController#index
ExampleClass can't be referred to from /Users/cameron/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/bundler/gems/activerecord-session_store-376ed7f7aba1/lib/active_record/session_store.rb:64:in `dump'
And that method that is failing in session_store.rb is:
def self.dump(value)
::Base64.encode64(Marshal.dump(value))
end
And the value it's trying to store is:
{"_csrf_token"=>"nrw4m2ZAECwD3TiaPZoaSt4vL1DvjO+COnBpUQGwpXs=", "example_class"=>#<ExampleClass:0x00007f7fa7b1b998 #field_one="field_one", #field_two="field_two">}
Why can I write the class in the first time around... but afterwards it throws that error?
And how we get around this?
I can't answer you fully why it fails, but I wouln't rely on implicit serialization of Ruby objects.
I would find a way to serialize the object of ExampleClass explicitly (similar to as_json) - convert to a hash, then store the hash in the session. When you need this object again, initialize ExampleClass instance with the params from session and then serialize it back to session.
I don't have an answer for why the above error happened but it turns out if you're storing an instance of a class inside the session, you're in fact storing the instance and not just the current state of the class as I originally thought it was doing.
This basically means that whenever you interact with that class and change it's attributes the session is still reading from the same instance you are interacting with and therefore has the same information without having to write back into the session.
In short you have the behaviour of a Singleton class but using a session to maintain state.

In GORM, Object is not modified in database when the object property is modified at Controller

In my Grails App, I have bootstrapped an object of a domain class as:
def user1 = new Users(userID: 1, name: "John Doe")
user1.save()
In my dashboard controller i have retrieved the object and modified its property name as:
Users userObj = Users.get((Long) 1)
println(userObj as JSON); // This gives me: {"class":"com.prabin.domains.Users","id":1,"name":"John Doe"}
userObj.name = "anonymous"
Now i create a new Users object to retrieve the changed object with same ID 1 as
Users otherUserObj = Users.get((Long) 1) // **Line 2** Is this retrieving from database or from GORM session?
print(otherUserObj as JSON)// This gives me: {"class":"com.prabin.domains.Users","id":1,"name":"anonymous"}
But the value of object in database is not changed. And even when i retrieve the Users object of same id 1 in another controller it gives me the initial object rather than the modified as:
Users userObjAtDifferentController = Users.get(1);
print(userObjAtDifferentController) //This gives me: {"class":"com.prabin.domains.Users","id":1,"name":"John Doe"}
My question is, if the value is not changed in the database, why it gives me the modified object at Line 2 though i have retrieved the object using GORM query (which i guess should retrieve from the database)?
I have also tried using save() after the modification but the result is same.
userObj.save() //doesn't show the changes in database.
My guess is that the object is not being saved to the database because some constraint(s) are invalid. You can determine whether this is the case by replacing your calls to save() with save(failOnError: true). If my guess is correct, an exception will be thrown if saving to the database fails.
When you call the save() method on a domain object, it may not persist in the database immediately. In order to persist the changed value to the database, you would need to do the following.
userObj.save(flush: true)
By using flush, you are telling GORM to persist immediately in the database.
In some cases when validation fails, the data will still not persist in the database. The save() method will fail silently. To catch validation errors as well as save to the database immediately, you would want to do the following
userObj.save(flush:true, failOnError:true)
If validation errors exist, then the GROM will throw ValidationException (http://docs.grails.org/latest/api/grails/validation/ValidationException.html)
You need to consider two things:
If you do save(), it only retains in hibernate session, until you flush it the changes does not persist in database. So, better do save(flush:true, failOnError: true) and put in try/catch block and print exception.
And another important things is, your method in controller needs to be with #Transactional annotation, without it your changes does not persist in database, you will encounter Connection is read-only. Queries leading to data modification are not allowed. exception.
Hope this helps, let me know if your issue is fixed. Happy coding . :)

Can I store a session variable from a method inside a model in Rails 3?

I tried to do the following:
20 session[:atoken] = linked_in_data['extra']['access_token'].token
21 session[:asecret] = linked_in_data['extra']['access_token'].secre
t
This is within a method inside of a User model.
But I get an error saying undefined method for session...why? Can session variables only be set in a controller?
It's a bad practice, but if you must do it :
http://m.onkey.org/how-to-access-session-cookies-params-request-in-model
But, finding a workaround is always better. Take a look at that as well :
http://media.railscasts.com/videos/119_session_based_model.mov
The session can't be accessed in the models. It would break somehow the MVC structure of the app. If you want to change the session values during save, update etc..., you can try to use sweeper.See the api. You can access the model's attributes, and the session as well, and you can observe changes of the object.

Resources