
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] || "
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 hereFor gems that work only with limited Rails functionality (for example, creating a new helper or controller filter), it is better to use
pluginsSo, 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 wroterails 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.
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.
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'
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.htmlhttp://blog.thepete.net/2010/11/creating-and-publishing-your-first-ruby.htmlRails in russianGem itself on github.comHe is on rubygems.org