This short article covers some steps you need to implement to get your own ActiveRecord implementation.
Sample ActiveModel looks like this:
First trouble is that ActiveModel does not provide any attribute access API. Or I did not google enough. So we need to create our own!
Let us have an instance variable @attributes where we will store our model’ data. We need to define getter and setter methods for all the attributes of our model. This may be done with the attr_accessor method. But when user sets the value for some attribute, we should store that in our @attributes variable. And here is the first step to our black magic: we will override the attr_accessor method.
I just wrapped the code into a single module. Remember: when you include the module in a class, all the module’ methods become class methods.
Now we will include this module before attr_accessor calls. But beware: you need to declare an @attributes instance variable in the constructor!
And let’s just agree with the following convention: all our attribute names should be symbols.
Now, we can implement our constructor. We now have all the attributes’ getters and setter and thus we can simply call them in our constructor:
Now let’s implement some basic model persisting. First, we should not forget about our validations and add valid? test to the save method.
Let’s say our save method should return the model instance. Thus, we should put the model’ data into the database and get the id for that data (if we put the data with the INSERT statement).
So there is an important caveat: in order to get the correct model id, you need to get it from database in the same transaction as the update/insert statement. The mysql2 gem does support multiple query statements in a single transaction. But to perform such a query, you will need to set the MULTI_STATEMENTS flag when creating a Mysql2::Connection instance.
Here I used the instance variable @connection to make it available within the rescue and ensure statements.
Now we will use our instance variable, @attributes to create an SQL query:
I used the ActionController::Base.helpers.sanitize helper method to escape the query parameters.
Now we should simply wrap our query into a transaction and get an id from the database.
Quite big method, sure. Yet, it performs all the UPDATEs and INSERTs for us.
Let’s add some attribute with the default value, created_at and check how the whole class works:
I am always being asked at least two questions. Just to verify that I know Ruby basics.
What is the main difference between Module and Class?
That is so simple and obvious! Yet it’s too easy to forget… The answer is: you can not instantiate a Module. See, Modules in Ruby do not have constructors. Yeah, they may contain variables, but they do not have an initialize method.
You could define one this way:
But when you try to call Moo.new you will get a method missing error. When you try to run Moo.initialize you will get a private method called error.
So yes, there is no way to instantiate Modules.
What’s the difference between Proc, lambda and block?
This is simple enough to remember as the answer contains only a few points:
Proc is an object; block is not
Proc does not check the number of arguments; lambda does
lambda returns from itself; Proc returns from the outer (containing the Proc call) method
What is REST (application)?
The answer on that question hardly depends on what the asking person means.
So, I got two possible correct answers:
a. That is the principle of web application development, when the application responds to a request, depending on which HTTP method was provided (PUT, GET, POST, DELETE, OPTIONS).
b. This is a way of encapsulation Resource and its Handlers. That is a bit hard to explain. Something like “you have to split your application to Resources”.
Does Module is the ancestor of Class or does the Class is the child of Module?
This question, actually, may be asked on Class, Module or Object classes. This question is interesting when you do not know the answer.
The reality is plain however:
So, you can even draw a chain:
Think oral. Show an interviewing person how your thought flow. That is the good practice. It shows that you can think not just remember. And you could get to some friendly talk when you say some magic keyword or tell something the interviewer is interested in.
When I am asked of Rails best practices, or just creating my web application, I should never forget one core principle: web application controllers (looking at Rails’ MVC) should be thin. So, the most logic at Controller’s action should get or set some data on Model and provide a response. Nothing more.
My web framework of choice is Ruby On Rails. It’s perfect for me. Not because of its scalability or performance, but because of its architecture. You do not need to do lot of work to create a website or a webservice. Ruby Gems have all the power you will ever need. Ruby itself allows you to do even a black magic nicely.
It’s true to say that i am a RoR fan.
So when i started learning JSF i thought Gosh! It’s ugly! It’s totally impossible to work with!. But in a while i realized that small yet mighty concept, i even did not imagine to be thinking of.
See, when you write a website, you need two things to be done:
give a user static content; user just should see something on a display!
take user data, process it and perform previous step; in order to make a dynamic website (which is 90% of all the websites you’ve seen, i guess) you should use web forms and process them
But in other cases you use resources. That’s the bundle of data, stored (maybe) in database and being controlled by user via the forms.
Any form (yes, just any) could be described as relying on some resource. Login form? It uses User resource. Search form? It uses the SearchQuery resource. Post creation form? It serves Post!
So, that powerful concept i was talking above is the principle a Managed Java Bean describes the Resource wired to the User Interface.
See, when you show a form to a user - you get your database row maped onto a Java Bean. When user saves the form with the new data - that data gets stored in the same Bean and the method you’ve set to commandButton or whatever is invoked.
Just think of it! You are doing exactly the same with all those Rails, Play, Django or any other web framework, when you are creating a dynamic website!
Just got the following error in my Rails project (Rails 3.2.6, Ruby 1.9.3):
ActionView::Template::Error (incompatible character encodings: UTF-8 and ASCII-8BIT)
That was caused by the case when MySQL record (ActiveReciord object, actually) contained UTF-8 characters and i was trying to output those chars in my template. But mysql gem does not support those. It needs some hacking.
Luckily, there is more convenient way to solve the problem. The solution of this issue now appears too easy:
Install the mysql2 gem
Use adapter: mysql2 instead of adapter: mysql in your config/database.yml file
My coursework: two months later. No, i was not doing all that stuff for two months - i… “freezed” the project for that time =P Actually, the greatest portion of job was done in one day - 22.04.2012 .. 23.04.2012 =)