Executing System Commands with Rails - ruby-on-rails

I am executing some system commands based on user actions such a mkdir,cd, cp -r skel/ dest/, and creating an apache vhost etc.
Where is the best place for this code to live? My instinct is to put them in the model as private methods, is this correct?
Thx
Jeff

Rails recommend having skinny controllers and fat models, but I believe that executing system commands is irrelevant to the model.
Since they depend of users actions, I'd suggest putting them in a library (/lib) and calling that lib from the controller.
Also, keep in mind that FileUtil might already do what you're looking for.

Instead of directly shelling out, I would advise using the FileUtils module, included with Ruby.
http://www.ruby-doc.org/stdlib-1.9.3/libdoc/fileutils/rdoc/FileUtils.html
require 'fileutils'
FileUtils.mkdir 'test'
FileUtils.cd 'test'
FileUtils.cp_r 'skel', 'dest'
I would also put them in the model as private methods.

Related

Where is a logical place to put a file flag?

In a Ruby on Rails application, where would the most logical place be to put a "file flag."
I am attempting to externalize configuration and allow the presence of a file to be the deciding factor on whether or not something shows on the webapp.
Right now, I have a file here:
lib/
deployment_enabled
Model deployment.rb
class Deployment...
...
def deployment_enabled?
Dir["#{Rails.root}/lib/deployment_enabled"].any?
end
end
Now this works of course, but i'm not sure this follows the MVC paradigms, since the lib directory should consist of scripts. I could put it in config, but again - not sure it belongs there as rails uses this for rails specific configuration, not necessarily the webapp.
I could of course put this in our database, but that require a new table to be created, and that seems unnecessary.
Where's the most logical place to put this flag file? Does Rails have a directory that's created during the generation to put these sort of files?
I suggest using the Rails tmp directory for this purpose. Then:
File.exist?("#{Rails.root}/tmp/deployment_enabled")
Phusion Passenger use this kind of mechanism too.
https://www.phusionpassenger.com/library/walkthroughs/basics/ruby/reloading_code.html#tmp-always_restart-txt
I recommend that you follow the Twelve-Factor App guidelines and keep your code separate from your configuration. In this case you are really talking about a simple boolean value, and the presence of the file is just the mechanism you use to define the value. This should be done instead through an environment variable.
Something like:
DEPLOYMENT_ENABLED=1 RAILS_ENV=production rails server
You would then use an initializer in Rails to detect the value:
# config/initializers/deployment.rb
foo if ENV['DEPLOYMENT_ENABLED']
The value can still be modified at runtime, e.g., ENV['DEPLOYMENT_ENABLED'] = 0.

Use Orchestrate.io with a basic Rails Application

I have a basic application running with ruby on rails. I use sqlite3 for development and postgres for production. I recently got access to Orchestrate.io and their student tier.
I would like to know how I could possibly use this with my application. I'm not even sure this is possible. My app is really simple (add-edit-delete). But it would be interesting to have a go at using the tools.
Mostly because I cannot find an efficient and free rails db text search.
You can definitely use Orchestrate as the backend for a Rails application.
A few different options:
The Orchestrate-Ruby client has both a method client & object client. Although the object client is still considered a work-in-progress, the method client provides a solid interface for connecting to the Orchestrate API.
Use an http library (such as rest-client or faraday) to make calls to the Orchestrate API.
There's also the Orchestrate-Rails gem. Your mileage may vary with this (last updated in April).
To use Orchestrate as the only backend (no postgres/mysql), I've found the best approach is to disable ActiveRecord:
When creating a new application, you can use -O to skip ActiveRecord:
rails new my_app -O
For existing applications:
1. Remove database adapter gems from your Gemfile (pg, mysql2, sqlite3, etc.)
2. Change your config/application.rb
Remove require 'rails/all line and require frameworks you want to use, for example:
require "action_controller/railtie"
require "action_mailer/railtie"
require "sprockets/railtie"
require "rails/test_unit/railtie"
3. Delete your database.yml file, db/schema.rb and migrations (if any)
4. Delete migration check in test/test_helper.rb
5. Delete any ActiveRecord configuration from your config/environments files (this is what is causing your error)
If you run into problems/errors, stack trace should give you sufficient information on what you need to change. You might for example have some ActiveRecord configuration in your initializers.
With the Orchestrate-Ruby client, you can define a model like so:
class Foo < Orchestrate::Collection
...
end
I'm still undecided on what the best approach for defining the Application object is, but one way I've done it is by making a global object with an initializer:
# /config/initializers/orchestrate.rb
$App = Orchestrate::Application.new(ENV['ORCHESTRATE_KEY']) # using dotenv gem
$App = Orchestrate::Application.new('your_key_here') # without dotenv
From here, you can then access the $App object in your controllers (to initialize the collection object):
class FoosController < ApplicationController
def index
#foos = Foo.new($App, "foos").each
end
end
Leveraging model concerns might be a better way to share the Application object/API key between models. Or you could roll your own classes on top of the method client.
Hope this helps!
I'll be looking into how to accomplish this in a more 'Railsy' way.
EDIT: also, textacular is a ruby gem which provides full-text search and indexing for postgres

Extend a Model from a Rails Engine (not replace it)

I have a Rails app that uses a gem called ActsAsTaggableOnSteroids, which is a Rails Engine. Specifically, I'm using PavelNartov's fork of the gem. But nevermind that.
I need to add specific functionality to the Tag model, which is supplied by the engine.
But, according to my understanding of Rails engines and the magical loading functionality in Rails, if I put a file called "tag.rb" in my models directory, then it will completely replace the one from the Engine.
Ideally, I would be able to do something like:
class Tag < ActsAsTaggable::Tag
# my stuff
end
...but alas, that doesn't work because the model supplied by the engine is not namespaced.
So, I came up with this nightmare, which I put in app/models/tag.rb:
path = ActsAsTaggable::Engine.config.eager_load_paths.grep(/models/).first
require File.join(path, 'tag')
Tag.class_eval { include TagConcern }
But there has to be a better way! I feel like I'm missing something. I'd prefer not to add this strangeness to my app if possible.
Just require the file by looking up the path of the gem's model:
require File.join(Gem::Specification.find_by_name("bborn-acts_as_taggable_on_steroids").gem_dir, 'app/models/tag')
Tag.class_eval do
# ...
end

Can I run a Rails engine's specs from a real app which mounts it?

I have a Rails Engine meant to provide some models and controllers to a larger project of ours. There's a pretty decent set of specs for the Engine, using a bunch of mocks and some full-scale models and controllers within the engine's dummy app to make sure the Engine is doing what it's supposed to and working with the larger application.
However, even with all tests passing, I frequently find broken behavior when I update the engine in the larger application. If my tests are passing but the behavior is broken, clearly something's wrong with the tests, but what? Am I mocking too much, or not enough?
To get me closer to figuring this out, I'd like to be able to run the engine's tests from inside the full application. This seems like it should be possible, but I don't understand rspec thoroughly enough to get a handle on how.
(This is related to this question but not quite the same; I'm not trying to run all the specs from one command, just to run the engine's specs within the full app environment. This also seems to be related. Actually, I've read every question tagged with both rspec and rails-engines--there aren't many--and they're all either not what I need, or unanswered.)
The simplest solution would be to specify the paths in rspec command. If you have directory structure
/project
/engine
/engine_2
Then you do and should run all the specs
cd project
rspec spec/ ../engine/spec ../engine_2/spec
But if you want to run specs on Continous Integration or just this doesn't seem to be comfortable I solved this problem with a customized rake spec task, changing the pattern method.
lib/task/rspec.rake should look like this
require "rspec/core/rake_task"
RSpec::Core::RakeTask.new(:spec)
task :default => :spec
RSpec::Core::RakeTask.module_eval do
def pattern
extras = []
Rails.application.config.rspec_paths.each do |dir|
if File.directory?( dir )
extras << File.join( dir, 'spec', '**', '*_spec.rb' ).to_s
end
end
[#pattern] | extras
end
end
In engine class you add a path to config.rspec_paths
class Engine < ::Rails::Engine
# Register path to rspec
config.rspec_paths << self.root
end
And don't forget to initialize config.rspec_paths somewhere in a base project.
If you want to add factories then you can create initializer, you can find solution somewhere here on stackoverflow.
Not sure if this solution is the best but works for me and I am happy with that. Good luck!

Exclude Sub Directory on Class Eager Load

I am facing an issue where my Rails application is set to cache classes when run in the staging or production environment. While load_paths only contains 'app/models', it appears that the initialization steps recursively caches everything in 'app/models'.
# Eager load application classes
def load_application_classes
if configuration.cache_classes
configuration.eager_load_paths.each do |load_path|
matcher = /\A#{Regexp.escape(load_path)}(.*)\.rb\Z/
Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
require_dependency file.sub(matcher, '\1')
end
end
end
end
The problem in this is that we have a sub directory within 'app/models' that contains files with require statements that reference a concurrent JRuby environment. Since Rails knows nothing of this environment our application breaks on load.
As it stands, here are the proposed solutions...unfortunately only #1 is ideal.
1) The simplest solution would be to exclude the culprit sub directory, but have not found anything how to accomplish this.
2) Monkey patch the load_application_classes method to skip the specific sub directory.
3) Move the sub directory out from under 'app/models'. Feels a bit hackish and would require quite a few code changes.
Thoughts?
As a temporary measure you could go with a version of option 2 and override the definition of load_application_classes, replacing it with an empty implementation. That would force you to explicitly require the classes you need but it would give you complete control over what gets loaded and would be a completely transparent solution.
It sounds like your application is sufficiently sophisticated that it's growing beyond the Rails framework. I know that this doesn't directly answer your question so appologies in advance but you may want to consider looking at an alternative Ruby framework like Merb. Rails is great but sooner or later you bump into edge of the framework - sounds like that's where you are now.
We made the switch to Merb last year and haven't regreated it.
Chris

Resources