Ruby on Rails on Windows with Performance Tests

    “The key to friendship is the difference of individuals” Julian Semenov.
    More and more, Windows developers are interested in Ruby, a dynamic, high-level programming language. A significant role here was played by the Ruby on Rails web application framework. Development on the “rails” is simple and fun. Due to the high dynamics of Ruby, a lot of auxiliary tools are opened for the developer, with a relatively small amount of code you get rich functionality.

    This article is good for beginner web programmers and those who are thinking of starting to work with Ruby on Rails. It will consider the following issues:
    • installation of a working environment;
    • writing a simple application;
    • Deploying the application on the server.
    In conclusion, you will find tests comparing the performance of various ruby ​​applications on Windows and Ubuntu.

    Setting the work environment



    First you need to download and install the Web Platform Installer, launch it, click on “Options” and in the “Display additional scenarios” field add a link to Helicon Zoo Feed: http://www.helicontech.com/zoo/feed/



    After that, The Web Platform Installer will display the Zoo tab, which contains the sections "Applications", "Packages", "Modules", "Engines":



    Install Ruby on Rails



    In the Engines section, you can put various frameworks, including Ruby on Rails 3.1 and 2.3. In addition, Ruby 1.8 and 1.9 are also available here. By default, installing Rails 3 puts Ruby 1.9 as a dependency. For Rails 2 Ruby 1.8 will be delivered.

    For convenience, the “Packages” section offers the “Ruby Hosting Package” package, which includes the following components:
    • Ruby 1.8.7 and Ruby 1.9.3;
    • Rails 2.3.11, 3.0.10 and 3.1;
    • Ruby DevKit (for building C-extensions);
    • popular jams: mysql2, pg, sqlite3, mongo_mapper, tiny_tds, activerecord-sqlserver-adapter, devise, authlogic, jekyll, formtastic, will_paginate, sinatra, ramaze, camping-omnibus, thin, goliath.


    Creation of the first website



    It’s convenient to use WebMatrix and IIS Express to create a new web application. On the “Zoo” tab, in the “Packages” section, there is a package “WebMatrix Templates”, which provides various template templates, including for Ruby on Rails.

    If you do not already have WebMatrix, it will be automatically installed with the WebMatrix Templates package. Be prepared that downloading and installing all packages may take some time. After installing the templates, launch WebMatrix and select “Site from template” on the start page and then “Rails Site”:



    After creating the Rails Site, if you go to the specified URL or click “Run ", You will see a page with instructions:



    The template is designed to create a Rails application branch 2.3, 3.0 or 3.1. At the moment, there is no application in the site directory yet, only prepared configuration files. Let's create it by calling the following command:

    rails new .

    If the command does not specify a specific version of Rails, the last available one will be used. In our case, we used the Ruby Hosting Package, which contains three different versions of Rails at once, and the most recent of them is 3.1. Therefore, the team will create a stub based on Rails 3.1.

    Now if you refresh the page, you will see the standard Ruby on Rails greeting:



    Development environment



    To edit the code you need an editor or development environment. If you prefer the functionality of a full-fledged IDE, with a debugger and refactoring tools, you can consider the following programs:Each IDE offers a ton of features for developing and testing Ruby applications, and also supports version control systems.

    For those who are used to using simpler solutions, available:To write an example, we used Aptana:



    MVC



    Ruby on Rails is based on the model-view-controller (MVC) architecture. This approach has the following advantages:
    • isolation of business logic from the interface;
    • as few code repeats as possible (DRY principle - don't repeat yourself);
    • relatively simple development due to the strict distribution of the code for the intended purpose (for example, the HTML form output code does not mix with the database processing code).
    The model describes the database structure in terms of object-oriented programming. So in Rails, a model is an ordinary class that inherits all the necessary functionality from the ActiveRecord :: Base class. An instance (object) of such a class describes one row from the corresponding database table. Thus, models hide from the developer the subtleties of working with a specific DBMS.

    A view is directly the interface that the user sees. At this level, the developer makes templates that are converted to HTML, CSS or JavaScript code.

    Controllerlinks the model and the view. Usually the main logic is placed in the controller. In essence, controllers are Ruby classes. Each public controller method is called an action. If your controller is called Home and it has a public index method in it, then usually requesting / home / index in the browser, you will call the index action.

    When a request arrives in the application, the routing mechanism (in the config / routes.rb file) determines which controller is responsible for this type of request. In addition to the URL itself, many conditions can be taken into account, for example, you can use different controllers for different browsers, for mobile clients, etc.

    So, having selected the controller, the action that will process the request is determined. Here you can also apply a lot of conditions. Directly in action, some kind of calculation or work with the database takes place. When the action has worked, the time has come for the presentation. You can transfer data or some result to the templates received from the database. Regular HTML will be generated from the templates (there are also templates for JavaScript and CSS) and the page with the response will be sent to the user.

    We are writing an application



    A classic example for Rails is usually to create a simple blog. Let's not backtrack on tradition. So, let's delete the greeting file - public / index.html and create the Home controller with the Index action - this will be the main page of the blog. To do this, execute the following command while in the application directory:

    rails g controller home index

    Now, if you request / home / index, we will get a page from the template created for the index action:



    Next, we will create a simple Post model that will describe every single blog post in the database. In Ruby code, the model looks like a class, and in the database it looks like a table. Thus, an object of class Post is a row in the corresponding table.

    To create a model, you can call the command "rails g model Post ...", but let's use a more convenient tool - scaffolding (scaffolding - scaffolding). The “rails g scaffold” team creates, in addition to the model class itself and the tests for it, predefined actions and presentation templates for creating, editing and deleting model objects.

    rails g scaffold Post name:string title:string content:text

    By executing the following command: We get the Post model in app \ models \ post.rb, the Posts controller in app \ controllers \ posts_controller.rb, with the actions index, show, new, edit, update, create and destroy, as well as a database migration script in db \ migrate directory. The team also created test blanks and HTML templates. It is important to note that we have not written any code yet.

    We call the command that will create the database (if it does not already exist), as well as the posts table with the name, title and context fields, as described above:

    rake db:migrate

    The database migration command is used to create or modify the database structure in accordance with our object model. It needs to be called up every time you change something in the application model. All the magic of fitting the database structure to our model occurs automatically, and the data already recorded in the database will be saved.

    Note that in a specific example, Sqlite is used, in Rails this is the default database. However, rails support a host of other DBMSs, while hiding the specifics of working with them.

    Posts controller actions are now available at / posts /.



    By clicking on the link “New Post” we will see the form:



    Filling all the fields, we get to the page of the new post:



    Once again, we remind you that no code has yet been written by hand. Now let's make some changes. For example, you may need to specify the name and title of the post so that this field is always filled in the database. Fortunately, Rails provides a very simple validation mechanism. It is enough to correct the model file as follows:

    class Post < ActiveRecord::Base
      validates :name,  :presence => true
      validates :title, :presence => true,
                        :length => { :minimum => 5 }
    end


    Here we indicate that the field “name” and “title” are required, and the field “title” should contain at least 5 characters. Migration is not necessary. validators are not directly related to the database; verification takes place at the level of ruby ​​code.

    If now, for example, you do not enter the "name" field, we get an error:



    We complicate the task and add comments. Create the Comment model with the following command:

    rails g model Comment commenter:string body:text post:references

    Pay attention to the “post: references” parameter. It links the comments table to the posts table.

    Update the database:

    rake db:migrate

    Now let's establish the “has many” relation for the Post model:

    class Post < ActiveRecord::Base
      validates :name,  :presence => true
      validates :title, :presence => true,
                        :length => { :minimum => 5 }
      has_many :comments, :dependent => :destroy
    end


    The code is intuitive. It turns out that each Post object can have many comments. : dependent =>: destroy indicates that when a post is deleted, its comments should also be deleted. Since this time we did not use the scaffolding mechanism to create a comment model, we need to generate the appropriate controller:

    rails g controller Comments

    In the config \ routes.rb file, replace the line " resources: posts do "on:

    resources :posts do
      resources :comments
    end


    Thus, we indicate how the controller with comments will be available. In this case, it is nested in posts, i.e. the links will look like this: http: // localhost: 41639 / posts / 1 / comments / 3

    Next, you need to update the app \ views \ posts \ show.html.erb template so that you can leave comments. After: add: Finally, we describe the logic of the controller in app \ controllers \ comments_controller.rb Now everything is ready and you can add comments to the post:

    Content: <%= @post.content %>





    Comments

    <% @post.comments.each do |comment| %>

    Commenter: <%= comment.commenter %>

    Comment: <%= comment.body %>

    <%= link_to 'Destroy Comment', [comment.post, comment], :confirm => 'Are you sure?', :method => :delete %>

    <% end %>

    Add a comment:

    <%= form_for([@post, @post.comments.build]) do |f| %>
    <%= f.label :commenter %>
    <%= f.text_field :commenter %>
    <%= f.label :body %>
    <%= f.text_area :body %>
    <%= f.submit %>
    <% end %>






    class CommentsController < ApplicationController
      def create
        @post = Post.find(params[:post_id])
        @comment = @post.comments.create(params[:comment])
        redirect_to post_path(@post)
      end
      def destroy
        @post = Post.find(params[:post_id])
        @comment = @post.comments.find(params[:id])
        @comment.destroy
        redirect_to post_path(@post)
      end
    end






    So, the main functionality is implemented. As a last step, let's protect some actions so that an outsider does not have access to them. A more correct approach is to use registration, sessions, cookies, etc., but for simplicity we will take basic Basic authentication, especially in Rails it is added as a single line. In posts_controller.rb we write:

    http_basic_authenticate_with :name => "admin", :password => "123", :except => [:index, :show]

    Here the username and password are rigidly specified. The: except parameter excludes the actions: index and: show - authentication is not required for them.



    Server deployment



    So, we wrote the application and now we want to put it on the network. To do this, configure the Windows server to work with Rails. We will need to repeat the first few steps from the beginning of the article that we did to deploy the working environment. You need to install the Microsoft Web Platform Installer, add Helicon Zoo feed to it and install the Ruby Hosting Package from the Zoo repository. Before installing, make sure that the Web Platfrom Installer settings instruct you to install applications under IIS, and not under IIS Express. Now the server is ready to accept our application. Currently, Windows 2008 and 2008 R2, 32 and 64 bit versions are supported from server platforms.

    Now create an empty web site on the server using the usual tools, such as the IIS manager or hosting panel. Next, you need to upload our application to the site via FTP or WebDeploy. In the case of WebDeploy, the necessary folder rights will also be distributed. You can also use Git or another version control system, but this is beyond the scope of this article.

    Helicon Zoo Module was originally designed with the configuration of hosting solutions in mind. So all applications under it are divided and do not overlap. The module with default settings works automatically, creating one worker (process processor) when the load is small or adding workers up to the number of cores to give maximum performance if the load on the application increases.

    Helicon Zoo uses the concept of engines and applications. So in the engines it is determined what to run and how, by what protocol and on which port, how many minimum and maximum workers are allowed and similar global settings that are set globally in the applicationHost.config file. Then, under the site, you can create an application that uses a specific engine and pass it the necessary parameters for this application to work. This allows the administrator to separate the hosting job on the clients and customers from each druga.Bolee details of Helicon Zoo Module settings can be read here: http://www.helicontech.com/zoo/module.htm (Eng.)

    Pay attention to the deploy.rb file in the root directory of the site, as well as the DEPLOY_FILE and DEPLOY_LOG settings in web.config. The Zoo module executes deploy.rb every time the IIS pool starts. This approach may be useful to those who do not have administrative privileges on the server. Indeed, for deployment, most likely, you will need to perform a “bundle install” or apply database migrations. To do this, simply restart your application on the server and the deploy.rb file will be executed automatically. The most popular commands are already registered in deploy.rb.

    It is also worth remembering that the deploy.rb script is executed by the same Windows user, which launches the IIS pool. As a rule, he has very limited rights and this should be taken into account when writing his commands. For example, a typical “bundle install” call may result in an error, since it is not possible to write directly to the Ruby installation directory. A good solution is to first save all the jams under the site in a special vendor / cache directory, for which you need to call the “bundle package” command in your application’s directory before sending it to the server. And in deploy.rb you should write the command "bundle install --local --path vendor / gems".

    Errors in executing the deploy script can be read in the file specified in the DEPLOY_LOG variable.

    The last thing I would like to pay attention to during deployment is the RACK_ENV variable in web.config. In the web.config that is set from the WebMatrix template, the RACK_ENV variable is specified with the value "development". This includes the appropriate mode in Rails, more suitable for development. On the server, you need to change the value to "production". By the way, it is production that is used by default.

    Performance tests



    The test machine as a server is Core 2 Quad 2.4 Ghz, 8 Gb RAM, a gigabit network. To generate the load, a more powerful computer and Apache Benchmark were used with the command “ab.exe -n 100000 -c 100 –k”. For testing Apache and Nginx, Ubuntu 11.04 Server x64 was used. IIS 7 tests ran on Windows Server 2008 R2. No virtualoks - honest iron.

    Three tests were performed. In the first Rails application, the application was simply to display the current time with high resolution on the page. Time is needed to ensure that answers do not come from the cache. The second test read from the MySQL database, the third write to the database.

    For tests we used Ruby 1.9.3, Rails 3.1.1 and MySQL 5.1.54. In the case of HTTP transport, Thin was used as a backend. Neither Unicorn nor Passenger on Windows just work. In total, three configurations participated in the test: Windows + IIS 7.5 + Helicon Zoo + Thin, Ubuntu + Apache + Passanger, Ubuntu + Nginx + Thin.

    Here are the results (the value on the graphs is requests per second):



    Also, according to the first test with time output, we give more detailed ab graphs:







    conclusions



    Ruby on Rails is a great framework that allows you to quickly and easily create various web applications. Of course, the Ruby world is not limited to it. In subsequent articles, we will look at Goliath and Sinatra.

    I would like to note that Windows is a good platform both for developing on Ruby and for launching applications in production. If before the difference in Ruby performance on Linux and Windows systems was high, now the productivity, as well as the convenience of using RoR on Windows, have improved greatly. So much so that now the issue of performance when choosing a platform can be neglected against the background of other factors.


    PS: The co-author of this article is Vyacheslav Shinkarenko. Because He is not invited to the Habr, then here is his Twitter: https://twitter.com/#!/vyaces

    Also popular now: