Reputation: 18080
What is the best way to create a new Ruby/Rails object without triggering any database actions?
For example if I have a Task class
class Task < ActiveRecord::Base
has_many :tags
has_one :location
end
And I want to create one from cached data that looks something like this
task_json = {
id: 1,
title: 'My Task',
tags: [
{ title: 'Tag1' },
{ title: 'Tag2'}
]
location: { lat: 46.0, lon: -120.1 }
}
And I want to reconstitute the object, but not trigger any database interactions.
@task = Task.new
@task.id = task_json['id']
@task.title = task_json['title']
@task.location = Location.new(:lat => task_json['location']['lat'], :lon => task_json['location']['lon'])
@task.tags = ...
Ideally, there would be no chance of saves or database interaction in any way once the object is built.
Upvotes: 4
Views: 10885
Reputation: 8096
What is the best way to create a new Ruby/Rails object without triggering any database actions?
For example if I have a Task class
class Task < ActiveRecord::Base
If you want a PORO (plain old Ruby object) that does not persist, why even subclass ActiveRecord::Base
? You could just put this in any autoloadable path like app/models/task.rb
:
class Task
attr_reader :tags, :location, ...
def initialize(...)
@tags = ...
@location = ...
...
end
end
Then create it elsewhere like:
task = Task.new(...)
And you can then access its parts like:
task.tags
Where you either pass in the parsed JSON, the JSON string, args, etc.
However, the hash itself from JSON.parse(some_json_string)
is a Ruby object, so you could just as easily use it. It won't trigger any DB operations either. :) The main reason you might use a class like Task is to make it a little more obvious what it is and what to expect from it, but a hash is easy enough to work with also. Just depends.
If you really want a read-only ActiveRecord model, you could use one of the several gems out there for it. I wrote one that a few others have contributed to called activerecord-be_readonly, but the times you'd need something like that should be few and far between, and it is more geared towards reading data from the DB and then attempting to not allow DB updates to that specific table via that model.
In your comment, you said you only want to make it read-only if pulled from cache, if I understand correctly.
Take a look at how the activerecord-be_readonly gem is altering AR behavior here: https://github.com/garysweaver/activerecord-be_readonly/blob/master/lib/activerecord-be_readonly/model.rb
I'm guessing you'll want to set a flag when you initialize the model with a JSON hash that similar methods could look at and raise ActiveRecord::ReadOnlyRecord
or similar when that flag is set.
This only protects the model that you use these methods in though. If you have associations to other models, it will not protect them unless they use a similar method. In the end, you may be better off with POROs and regular AR models, if you absolutely must do this.
However, this sounds like it is going to be a pain to use. I'd avoid anything that makes the user (or developer) scratch his/her head too much.
Upvotes: 2
Reputation:
You can try to use JSON.parse
on your JSON string task_json
this way:
task = Task.new(JSON.parse(task_json))
Upvotes: 8