📜 ⬆️ ⬇️

Rails 4 Engines. Gem development through mountable engine - we read server logs


It so happened that there was an overwhelming desire to write your own Rails gem. Firstly, academic interest - this has not yet been done, and secondly, there is a problem, the solution of which is important for me personally and which I would like to use in several of my projects.

On Habré there were already articles about the creation of gems ( one two three times )

But based on them, it is impossible to create a full-fledged gem - they are very outdated and, as a rule, constitute a translation of the mean official documentation. And most importantly, they mostly describe the creation of the Readme and License files, and the gem functionality itself comes down to Hello World.
')

Problem


I do not know how anyone, but I regularly have a situation - screwed a new feature locally, checked it, it seems to work. You start cap deploy, you look at the server, and there
“Sorry, but something went wrong.
If you are an application owner, check the logs for more information. ”

Well, then - ssh to the server, cd to the application folder and the excavation of logs. Whatever fans of vim and emacs may say, but trying to find something in the log with their help is something else. It's easier to run tailf and try to find it with your hands. There is still rmate, but I somehow did not catch on.

Idea


Write a gem that will output the results of the tail command to the browser in the specified path. It is advisable to be able to watch all .log files in the log / folder

Immediately show what happened in the end:


All you need is to register in a gemfile
gem 'tail' 

install gem
 bundle install 

and mount it ( config/routes.rb ) at the desired point of the application, for example
 mount Tail::Engine, at: "/tail" 

After that on your server
This page will appear:

Locally works the same way.

If the application uses Devise, you will first need to enter a username and password.

How to do


Sinatra-based gems are usually used for such cases ( for example )
Personally, for my gem, I do not see the point, because I use Rails and there is no need for a synatra.

For a start, it makes sense to write the application itself, which will later be turned into a separate gem.
In my case it will consist of one controller and one action:

  class LogsController < ApplicationController before_filter :authenticate_user! if defined? Devise def index @web_logger ||= Log.instance @web_logger.n = params[:n] log_file_name = params[:file_name] || "#{Rails.env}.log" @files = @web_logger.tail(log_file_name) end end 

Everything is simple, we use one Singleton class, which gives the specified number of lines from the specified .log file. Log class itself is of no interest. Is that the way to get the log:

 @files.include?(file_name) ? `tail -n #{@n} log/#{file_name}`.lines : [] 

Ruby natively allows you to execute OS commands by simply enclosing it in these (hell knows how correctly they are called) characters: `tail -n 40 production.log` will return the last 40 lines from the file.

The resulting lines are placed in a table, slightly refined by CSS and displayed on the screen.

One line of JavaScript (the well-known framework - Vanilla.js ) scrolls the screen down to the last line:

 'window.scrollTo(0, document.body.scrollHeight);' 


Making a gem from the application.


Articles on Habré and the respected Ryan Bates described the creation of a gem using the bundle gem command. The last video dates back to November 2011.
Now the creation of Rails gem'ov recommended to do through engines .

Engine is essentially another Rails application that will run along with the original one and use (mutually) its resources. Siamese twins, in general. Or implants, as someone more like. In the parent application, the connection point of the new engine / plugin / gem is indicated, and then all the functionality of the new application is available at this address. The explanation is primitive, on the fingers, to whom the details are interesting - I have indicated the links below.

Thus, it is quite convenient to implement all admins, statistics gems, activity monitoring, etc. In general, everything that, on the one hand, is relatively independently and not so closely intertwined with the main application, and on the other hand, uses the full functionality of Rails - models, controllers, views, etc.
Otherwise, it will be necessary to seriously sweat with the order of application initialization, migrations, access control, security, etc. Golovnyak is still, but nothing is impossible. Who is interested - you can start with this article here

For gems that work only with limited Rails functionality (for example, creating a new helper or controller filter), it is better to use plugins

So, create a future gem named tail

 rails plugin new tail --mountable 

The --mountable key actually separates the creation of the mountable engine from a relatively simple plugin.

In my case, I wrote
rails plugin new tail --mountable --skip-active-record
As I do not use work with base.

Very fun team. If you look at the folder structure created as a result, it will be a mixture of the usual Rails application and the result of the bundle gem command.

Three main points:


The first

the lib folder will be the basis of the future gem and the most important file in it is engine.rb
 module Tail class Engine < ::Rails::Engine isolate_namespace Tail end end 

A module called gem is created with an isolated namespace in which all your models, controllers, views and classes will be wrapped. Those. instead of the SomeClass class, you will have Tail::SomeClass , the same with routes and paths - instead of, for example, messages_path you will write tail.messages_path if you need to get into the gem web part.
By itself, this is done in order to eliminate conflicts of the name of the gem and applications where it will be mounted.

Pay attention to the folder structure app/ in the application: in each of them added an additional subfolder called gem'a, to which the necessary files are added. Affects file and helper paths.
Hidden text


Second one

.gemspec file - besides the description of the pesonal information, it contains a list of dependencies on other gems and a list of files required for assembly.

lib / version.rb is the gem version number. It is recommended to use the notation described in semver.org . A simple thing, but I draw attention to it, because the next publication of gem'a without changing the version is not allowed.

And third:

test / dummy folder - this contains the fake application that is already mounted (/test/dummy/config/routes.rb). Ie, in order to check the work of gem, it is enough to go to this folder and run rails server. At localhost: 3000 / tail will be my application. Really very comfortable.
Hidden text


Fill gem


 rails generate resource log 

I do not use scaffold, because there is no need for CRUD and generation of views.

I transfer the code from the existing classes to the generated files. It is worth making sure that everything works by running the fake application from test/dummy .

Everything, from this point on, gem can be connected and debugged in another application:
 gem 'tail', path: '~/projects/tail' 

or
 gem 'tail' , git: 'git://github.com/k2m30/tail.git' #   push  github 

The main thing to remember is to update the version file and bundle update tail in an application that uses gem after each change.

Publication


To publish a gem on rubygems, you need to register there.

After that, in the folder of the gem project
To build gem
 rake build 

Auxiliary team
 gem push 

It is not involved in gem creation, it’s just an easy way to specify rubygems credetnials for release. It is necessary to enter only once.

Actually publication.
 rake release 

Immediately after this, the gem will appear in the search for rubygems and will be available through gem install for other developers.

Total


1. To create a mountable Rails gem, do the following:
create skeleton
 rails plugin new tail --mountable 

2. Fill it with a familiar Rails application.
There are minor features, but they are few and well described.
It's very easy to see what you did by running rails server in the test/dummy/ folder test/dummy/

3. Assemble a gem
 rake build 

4. Register at rubygems.org and specify your username and password:
 gem push 

Make a release
 rake release 

That's all, you are a happy owner of your own gem.

By the way, at the time of publication, rubygems claims that my gem was downloaded 151 times already. Not really believe it, but nice.

In general, the development was focused on ease of installation and use - nothing superfluous. Totally. Although there are other options - for example, gem webtail sends the contents of the log to the socket and, accordingly, you can watch the changes in the logs in real time. Such a realization does not suit me, if only because an additional dance with firewalls is needed. Although beautiful.

I really hope that my article, and who knows it, the gem itself will be useful and will save someone time and nerves.



Links


http://wangjohn.imtqy.com/railties/rails/gsoc/2013/07/10/introduction-to-railties.html
http://blog.thepete.net/2010/11/creating-and-publishing-your-first-ruby.html
Rails in russian
Gem itself on github.com
He is on rubygems.org

Source: https://habr.com/ru/post/216141/


All Articles