How do I handle data which must be persisted in a database, but isn't a proper model, in Ruby on Rails? - ruby-on-rails

Imagine a web application written in Ruby on Rails. Part of the state of that application is represented in a piece of data which doesn't fit the description of a model. This state descriptor needs to be persisted in the same database as the models.
Where it differs from a model is that there needs to be only one instance of its class and it doesn't have relationships with other classes.
Has anyone come across anything like this?

From your description I think the rails-settings plugin should do what you need.
From the Readme:
"Settings is a plugin that makes managing a table of global key, value pairs easy. Think of it like a global Hash stored in you database, that uses simple ActiveRecord like methods for manipulation. Keep track of any global setting that you dont want to hard code into your rails app. You can store any kind of object. Strings, numbers, arrays, or any object."
http://github.com/Squeegy/rails-settings/tree/master

If it's data, and it's in the database, it's part of the model.

This isn't really a RoR problem; it's a general OO design problem.
If it were me, I'd probably find a way to conceptualize the data as a model and then just make it a singleton with a factory method and a private constructor.
Alternatively, you could think of this as a form of logging. In that case, you'd just have a Logger class (also a singleton) that reads/writes the database directly and is invoked at the beginning and end of each request.

In Rails, if data is in the database it's in a model. In this case the model may be called "Configuration", but it is still mapped to an ActiveRecord class in your Rails system.
If this data is truly static, you may not need the database at all.
You could use (as an example) a variable in your application controller:
class ApplicationController < ActionController::Base
helper :all
#data = "YOUR DATA HERE"
end
There are a number of approaches that can be used to instantiate data for use in a Rails application.

I'm not sure I understand why you say it can't fit in a Rails model.
If it's just a complex data structure, just save a bunch of Ruby code in a text field in the database :-)
If for example you have a complex nested hash you want to save, assign the following to your 'data' text field:
ComplexThing.data = complex_hash.inspect
When you want to read it back, simply
complex_hash = eval ComplexThing.data
Let me point out 2 more things about this solution:
If your data structure is not standard Ruby classes, a simple inspect may not do it. If you see #<MyClass:0x4066e3c> anywhere, something's not being serialized properly.
This is a naive implementation. You may want to check out real marshalling solutions if you risk having unicode data or if you really are saving a lot of custom-made classes.

Related

Persist a single variable in rails

I want to store a single variable across all my users in a rails application.
This variable is just an integer that can change sometimes.
I want it to persist across different launch of the server.
I want any controller to be able to change (and persist) the value
It sounds really easy to do, but I can't find any tool that would do it for me...
I would create a Key/Value table and model.
So far, it would only store one key, the integer you're talking about. Later, it could do a little more. The value could be a JSON document so you can store any kind of JSON supported native types very easily.
Simply create a model with one attribute. And then create one instance of that model. Then access this from your controllers
for example
Model.first.attribute
I ended up using the gem rails-settings-cached
It provide an easy way to access a persistant variable:
Setting.a_setting = 42
Setting.a_setting #42

ZF2 - database and models

I followed this examples http://framework.zend.com/manual/2.2/en/user-guide/database-and-models.html to create a model and a way to save it to a database.
But I don't like the idea of using the AlubumTable-class in my controller as I think this creates too much dependencies. I just want to add the save(), fetchAll(), etc. methods to my model so that I don't have to care about how to save my models inside my controller.
If I want to change the way my models get stored e.g. from a database to a REST-service I would have to rewrite every part of my controller where I get or store models instead of just changing the save() etc. methods in my model.
Are there any tutorials for my way or is this just a stupid idea? :)
The concern you have is actually OK, but you have to realize that the AlbumTable is nothing but a layer between your Controller and the Database. The AlbumTable actually is the one thing with the dependency, not the controller.
The Controller will always need some sort of "Service" or "Gateway" (which would be AlbumTable) to get access to the Data from the DB.
Also i do not understand what you mean by "i want to change the way my models get stored" - You should always store the MODEL into your Service. In the given example the Model is Album and the Service is AlbumTable. No matter where the data comes from - REST, RPC, "normal HTTP", you would always store the Album and not some ArrayData or whatnot. You'd rather try to implement a function inside your model like exchangeArray(), exchangeJson().
You may want to make your "problem" more clear to us...

Should I make a new Class in Rails for Redis?

I'm starting to use Redis, and first thing my code is not too DRY, and was going to consolidate it in the application.rb and controller. Is this the best way to go, or should I make a new Class called Redis, and have all the logic in there?
My models are currently Customers, Orders, Products, and I'm using a lot of counters.
You will probably need a combination of new and existing model classes.
In many cases you can just drop the model used by the view directly into the datastore, which saves repetition. However, there will always be some places where the needs of the view and the datastore are different.
For example a property that appears as a list of values in the view may need to be stored as a separate set key rather than serialized with the other properties of the model.

Best practice to isolate data access layer in Ruby/Rails

So, I have Ruby on Rails application. Blank for now. And let me say right from the beginning that most of my experience is from Java, so I might be thinking not the way RoR devs do. :-)
What I need to do is to create some Data Access Layer, say it will be access users, so let it be
UserDAO.rb which will be basically then using ActiveRecord or directly accessing the database or accessing or some key-value storage or anything else I can think of.
Technically, as we don't have interfaces in Ruby, I can make UserDAO.rb to "have" the implementation (basically, I am talking about composition), which may be anything we need, say UserDAOActiveRecord.rb or UserDAOMongo.rb or anything else like that. UserDAO.rb will basically call the methods of the implementation and that's it. Should be easy to switch between implementations.
While it does sound like a possible solution, I am looking forward to hear what are the best practices for this problem in the Ruby world. Thanks!
You will have to look for a Ruby Class other than ActiveRecord (which as pointed out is an Object Relational Mapper, so has no separate data access layer).
You might want to look at: https://github.com/jeremyevans/sequel
You could create a class, Person, which contains methods which use an instance of Sequel to talk to the database.
This untested code demonstrates why this might not be a great idea:
class Person
attr_reader :first_name, :last_name
DataSource = Sequel.sqlite('my_app.db')[:people]
def initialize(record)
#first_name = record.first_name
#last_name = record.last_name
end
# Find a record from the database and use it to initialize a new Person object
def self.find_by_id(id)
self.new(Table.where(:id => id))
end
end
Remember that ActiveRecord isn't only a way to access a database, it's also a pattern for how your data is integrated into your application: the idea that each model controls its own data and stores/retrieves/queries it as needed, with a model instance representing a database row.
Naturally, you don't have to use that pattern, but it's one of the cores of Rails, so by treating ActiveRecord as just another data access method to be abstracted, you're losing a lot of functionality.
Note also that ActiveRecord already abstracts out the database type by using a database adapter, so it's easy to drop in MySQL, Oracle, etc. But it does assume a relational database.
However, to answer your question, it's not really necessary to wrap your data access implementation in another class just to ensure a consistent interface. As you say, ruby doesn't have Java-type interfaces, but the ruby world also doesn't generally try to ensure that developers can only do legal things. You can create a bunch of data access classes that offer the same set of methods, create unit tests to ensure that those methods are consistent (and to act as executable documentation of those methods), and then trust developers to make the correct calls against whichever implementation they pick. It's a big cultural difference from the Java world, where everything is coded to interfaces and methods are final and objects are immutable. It takes some getting used to.
Alex, I strongly suggest you to get the book Agile Web Devoplment With Rails (4th edition). Active Record implements the ... active record pattern, so the Class is the DAO (the class methods represent the dao), while the instance methods represents the object.
So for example you can have
person = Person.find(3) //Person is the dao
person.name = 'mick' //name = is the setter for he instance
person.save // well.. saves the object
I've coded in Java for 10 years and just started with ruby..... and it's quite a change.

Creating the same model from multiple data sources

This is mostly of a design pattern question. I have one type of model that I'm going to get the data to create them from multiple sources. So for example one record my be created from an API where another is created via screen scraping with Nokogiri.
My issue lies in how best to abstract out these different data sources. Right now I'm building lib classes that return the same hash which I then use to set the attributes of the model. But I'm wondering if this isn't more of a case to use STI. Or if there is some other way of doing this I'm just not thinking about.
I think your design decision would depend largely on what attributes need to be stored. From your description, it sounds like you have a model with multiple data sources, but which would be storing the same attributes regardless of the source. In that case STI seems like overkill. When you retrieve a row from the table, does it matter whether the source is the API or the screen scraper? If not, then you could just define separate methods for each data source and use the appropriate method in the controller.
#instance = MyModel.new(:datasource=>"API")`
I'd say don't worry about inheritance (or mixing in code from modules) unless you really need to. There are some gotchas -- STI is not fully supported by some gems/plugins, for example.

Resources