ActiveRecord - prevent DB connection when calling Model.new - ruby

Every time I call Model.new, and before calling .save, ActiveRecord seems to get a database connection (which might make sense since it needs to get the field names).
How do I prevent this from happening? I don't intend to save the model into the database. I'm just creating it and then passing it to other functions.

Why don't you create a version of the model that doesn't inherit ActiveRecord::Base Then you can pass it around as a data object and leave your database alone until you actually need it.

Related

Strong consistency for a Rails model in Mongoid 3

I want all of my db interactions for a specific model to go through the mongo primary in my cluster, so I set the model to use strong consistency.
class Photo
include Mongoid::Document
with consistency: :strong
field :number, type: Integer
# let's say a photo number is unique in the db
validate :unique_number
end
But this does not seem to work, because I still run into validation errors when I save two Photo photos very close together.
photo1 # db has number=1 for this object
photo1.update_attributes(number: 2)
photo2.number = 1
photo2.save! # <= this raises a validation exception
My understanding of strong consistency is that there shouldn't be a race here. It should do the write and then do the read, and since it's all off the primary there shouldn't be a conflict. What am I missing?
What you area experiencing looks like it is persistence. The update_attributes is making an atomic change on the document, and it looks like it is not updating the persisted photo1.Your photo2 validation is fired from within the persistence (i.e. on the rails server and not in mongo) and is looking at the records it has. If you ran photo1.reload after the photo1.update_attributes this may sort this for you.
It's been a while since I used mongoid 3, 4 has been the staple for a while and recently upgraded to 5.You won't find this type of issue in mongoid 4.
If the reload does not help, please output photo2.errors so I can pin point the issue for you.
It turns out calling with(consistency: :strong) at the class level only applies it to the next query. So the class method is called when the class is loaded, setting strong consistency for the first query,
but subsequent queries don't trigger the same class method leaving their persistence operations to operate with eventual consistency. From the Mongoid 3.1.7 documentation:
Tell the next persistance [sic] operation to store in a specific collection, database or session.
This method does not enforce the persistence options that can be passed in (like a few other methods in the class), so we can also pass in consistency: :strong.
Hack Fix
In order to apply this to every* persistence operation, I added it to a default_scope.
class App
default_scope -> { with(consistency: :strong); where({}) }
end
In this case, the default scope expects to have a Mongoid Criteria object returned, so we return a noop where clause after setting the consistency level on the in-progress persistence operation.
* This will not be applied if the developer decides to call unscoped and strip off the default_scope.

Ruby - Sequel Model to access multiple databases

I'm trying to use the Ruby Sequel::Model ORM functionality for a web service, in which every user's data is stored in a separate MySQL database. There may be thousands of users and thus databases.
On every web request I want to construct the connection string to connect to the user's data, do the work, and then close the connection.
When using Sequel, I can specify the database to use for a particular block of code:
Sequel.connect(:adapter=>'mysql', :host=>'localhost', database=>'test1') do |db|
db.do_something()
end
This is all very good, I can perform Sequel operations on the particular user's database. However, when using Sequel::Model, when I come to do my db operations it looks like this:
Supplier.create(:field1 => 'TEST')
I.e. it doesn't take db as a parameter, so just uses some shared database configuration.
I can configure the database Model uses in two ways, either set the global DB variable:
DB = Sequel.connect(:adapter=>'mysql', :host=>'localhost', database=>'test1')
class Supplier < Sequel::Model
end
Or, I can set the database just for Model:
Sequel::Model.db = Sequel.connect(:adapter=>'mysql', :host=>'localhost', database=>'test1')
class Supplier < Sequel::Model
end
In either case, setting a shared variable like this is no good - there may be multiple requests processed concurrently, each of which needs its own database configuration.
Is there any way around this? Is there a way of specifying per-request db configuration using Sequel::Model?
As an aside, I've run into a similar problem with DataMapper, I'm now wondering whether having a single multi-tenanted database is going to be the only option if using Ruby, although I'd prefer to avoid this as it limits scalability.
A solution, or any pertinent discussion would be much appreciated.
Thanks
Pete
Use Sequel's sharding support for this: http://sequel.jeremyevans.net/rdoc/files/doc/sharding_rdoc.html
Actually in your case it's probably better to use arbitrary_servers extension than sharding:
DB.with_server(:host=>'hash_host_b', :database=>'backup') do
DB.synchronize do
# All queries here default to the backup database on hash_host_b
end
end
See:
http://sequel.jeremyevans.net/rdoc/files/doc/sharding_rdoc.html#label-arbitrary_servers+Extension

How to check whether an instance of an ActiveRecord model is up to date?

For testing reasons, I want to check that one of my methods doesn't update a specific entry in my database. Is there a simple way to ask an instance of an ActiveRecord model if its in sync with the database? for instance, if we had a method foobar? that could do this:
old_post = Post.find(1)
updated_post = Post.find(1)
updated_post.update_attributes(name: "this is a new name not like the old name")
old_post.foobar? #should return true, as its attributes are no longer up to date
updated_post.foobar? #should return false, as its attributes match the database directly
So is there a method that acts like foobar, or something like it? Thanks in advance.
I think your problem lies beyond finding a method which tells you wether an attribute has been updated, but in the relationship among the different objects that are instantiated. First it is important to understand, that old_post and updated_post are unrelated ruby objects. They know about how to save their own state to the database, but they do not know about each other.
Therefore your first requirement for foobar? cannot be fulfilled, as old_post will think it is up-to-date as long as no attribute has been updated. In contrast the changed? method will roughly answer in the way you are trying to achieve for updated_post. However it does so because it thinks nothing has happened since it was last saved, this will not be verified against the database upon each call of changed? as this would be wasting a database call in 99.9% of all cases.
This means it is all too easy to generate anomalies between the objects you created as there is no direct connection between the two (except the implicit connection that they once represented the same database row). If you change an attribute in one object (using e.g. title='?' it will change the value of the object and take note of the change in the changed-array. Once you save this object it will save its changed attributes to the database (by creating an individually constructed update-statement).
Another object that is already instantiated (as old_post in your example) will not know about this change and might change other attributes if you are not careful (or even the same ones if they have been changed again). Depending on your database adapter you may try to use the lock! method which will synchronize your object with the database before allowing any modifications. This however will not happen automatically as in most controller methods updates do not conflict nearly often enough to merit the synchronization as it will be idempotent in most cases.
This does not go without saying that rails can not save you from thinking about your transaction semantics if you want to guarantee specific ACID semantics for your controller methods.

Store a class instance in session server side w/ Padrino?

I have a class that reads from a DB on startup. I'd prefer to be able to store it in the session, but I get the following error when trying to do so:
ERROR TypeError: no marshal_dump is defined for class Mutex
Is what I'm doing possible/reasonable? If so how should I go about doing it? If not, whats a good alternative to storing the class instance in the session? Currently my workaround is just instantiating it whenever I need to use it, but that doesn't strike me as a good solution or one that will be able to scale.
A good alternative is to store the id of the record in the session. Then when you need that data again you'd use a helper to return the data either from memory or from the database. A perfect example is the pattern used in current_user helper methods found in many ruby authentication gems. You could modify this helper to use a cache layer if you find it to be a bottleneck, but I'd leave that as an optimization after the fact.
Issues of having to get the object into a marshaled format that will live happily in a session, there are issues with storage space, stale data and possibly unintentional exposure to confidential data.

How to provide parameters when initializing a ActiveRecord model in Rails

I have read allot of questions on here about different ways to initialize a ActiveRecord model properly when dealing with initializing values and is always in relation to providing default values. A great answer I came across helped clarify different ways.
However, if it is frowned upon to override the ActiveRecord base initialize method, what is the proper way to provide parameters to an ActiveRecord model when you want to initialize with values as you would in a standard Ruby class initialize(arg1, arg2...) method.
so you can
obj = MyObject.new(Obj1, some_num)
The only thing I have come across was actually overrideing the initialize method but calling super first in the initialize. However, this was frowned on because ActiveRecord's base class uses allocate in allot of cases to instantiate an AR object and therefore could end up sidestepping the entire initialize method.
So, maybe there is another fundamental reason why I am not finding providing initial values as a standard practice in RoR?
I know I can use validates in the object to validate an object can't be saved without meeting requirements, such as having all the proper attributes set. But I was approaching this particular object, so that it wouldn't be created without the required attributes when it is initialized to begin (since at initialization we would have all that information and if retrieving from the DB we would have all those values).
Can someone help direct me?
extra question
If there is an accepted way to do the above, there seems to be another area that needs to be considered when initializing objects with values and that is when the object is initialized from being retrieved from the DB. Not handling the initializing values properly can possibly override what is retrieved from the DB (or I have read when related to setting attributes to default values). So if that needs to be handled properly, how do we do that?
You can provide a hash of values when you initialize an ActiveRecord object. This is used in the create action of the controller to create a new object based on the data collected in the new action.
For example:
def create
#book = Book.new(params[:book])
where params is a hash of the values for the new object.

Resources