Execute migration files dynamically - ruby-on-rails-3

How can we execute a mignation file dynamically from the source code. Means we want to execute a migration file from an action of a controller. How can we do so?

The main issue was that we do not know the names of migration files. I do it with the following code
ActiveRecord::Migrator.migrate("vendor/plugins/#{self.id.to_s}/lib/db/migrate/", nil)
Package::Rake.call('db:schema:dump')
And the Rake class have the following method
def call(task, options={})
options[:rails_env] = Rails.env
args = options.map { |n,v| "#{n.to_s.upcase}='#{v}"}
system "rake #{task} #{args.join(' ')} --trace >> #{Rails.root}/log/rake.log &"
end
Hope this will help some body with similar problems.

This is assuming the migration is static and in your db/migrate directory when the app server starts:
You could add the migrations directory to your autoload path in config/application.rb, and then require the migration file to be run inside your controller (or in a config initializer):
application.rb
config.autoload_paths += %W(#{Rails.root}/db/migrate)
your_controller.rb
require '20101209102033_some_migration_file'
#....
SomeMigrationFile.up
I would be interested to know what the use case is here. Seems pretty wild!

Related

In Rails 5, setting config.active_record.schema_format = :sql but still getting schema.rb created on db:migrate

Working on a Rails 5 app, I want to use structure.sql instead of schema.rb (we're using PostGIS with lots of custom SQL calls...). In config/initializers/database_options.rb I have the following:
# use structure.sql, not schema.rb
Rails.application.config.active_record.schema_format = :sql
If I run the following:
$ rake db:migrate
it generates db/schema.rb, not db/structure.sql.
The rails guides say:
There are two ways to dump the schema. This is set in
config/application.rb by the config.active_record.schema_format
setting, which may be either :sql or :ruby.
What magic am I missing here?
I think you should put your rails component config before Initializers.
The rails application initialize by the following order.
config/application.rb
Environment-specific configuration files
Initializers
After-initializers
You could put your config config.active_record.schema_format = :sql either in config/application.rb or config/environments/development.rb depends on environment you used.
That should work.
In your initializer do:
Rails.application.configure do
config.active_record.schema_format = :sql
end

Capistrano deploy fails due to missing manifest file when using assets prefix

I've just set up a Capistrano deploy for our application and I keep running into this error:
* executing ["ls /path/to/app/shared/assets/manifest*"]
servers: ["web03"]
[web03] executing command
[err :: web03] ls: /path/to/app/shared/assets/manifest*
[err :: web03] : No such file or directory
If I manually create a manifest file with touch /path/to/app/shared/assets/manifest.yml, the deploy script works fine. However, this feels all sorts of sketchy.
I've googled the heck out of this and the most I can gather is that the manifest file it's looking for is a product of the asset pipeline. I checked and I do, in fact, have the pipeline enabled (config.assets.enabled = true), so I'm at a loss.
Could someone please help me understand 1) what this manifest file is and how it's created; and 2) why isn't one being created for my application?
Update: I think I'm closing in on the answer and I think it has something to do with this line:
config.assets.prefix = "/some_other_path"
We needed to rename the "asset" path because we have Asset objects in our system and I'm guessing Cap might be getting confused because of it. Any suggestions?
My suspicion was right: this was a problem with the renamed asset directory. Cap didn't know to look in public/some_other_path instead of public/assets.
In other words, because this line is in my application.rb:
config.assets.prefix = "some_other_path"
I had to add this line to my deploy.rb:
set :assets_prefix, "some_other_path"
Then, Cap knows where to look for a manifest, copies it into shared/assets, and finishes correctly.
It'd be handy to have the deploy.rb reference the config variable instead of having to hard-code the path a second time, but that's outside the scope of this question.
if you configure with the aws, here it should be...
appname/config/environments/production.rb
config.action_controller.asset_host = "//#{ENV['FOG_DIRECTORY']}.s3.amazonaws.com"
config.assets.prefix = "/#{ENV['APP_NAME']}/assets"
appname/config/deploy.rb
...
set :keep_releases, 5
set :assets_prefix, ->{ "#{fetch(:application)}/assets" }
set :whenever_identifier, -> { "#{fetch(:application)}_#{fetch(:stage)}" }
...

Using Compass on Heroku: /tmp for stylesheets remotely and locally

I'm currently using Compass with Heroku using this configuration recommended on the Heroku knowledge base. Heroku has a read-only file system, and so the compiled stylesheets need to be stored in /tmp. This works fine remotely on Heroku; locally, however, Rails expects to find stylesheets in /public/stylesheets (when called through = stylesheet_link_tag 'screen.css', :media => 'screen, projection').
In order to solve the problem, I have created symbolic links in /public/stylesheets using ln -s tmp/stylesheets/screen.css public/stylesheets/screen.css and that seems to work.
Is there a way to solve this problem without using symbolic links, perhaps by changing some configuration in Rails? I've poked around without much success.
Here is my config/initializers/compass.rb:
require 'compass'
require 'compass/app_integration/rails'
Compass::AppIntegration::Rails.initialize!
# Required for Heroku:
require 'fileutils'
FileUtils.mkdir_p(Rails.root.join("tmp", "stylesheets"))
Compass::AppIntegration::Rails.initialize!
Rails.configuration.middleware.delete('Sass::Plugin::Rack')
Rails.configuration.middleware.insert_before('Rack::Sendfile', 'Sass::Plugin::Rack')
Rails.configuration.middleware.insert_before('Rack::Sendfile', 'Rack::Static',
:urls => ['/stylesheets'],
:root => "#{Rails.root}/tmp")
And here is my config/compass.rb:
project_type = :rails
project_path = Compass::AppIntegration::Rails.root
# Set this to the root of your project when deployed:
http_path = "/"
# Necessary for Heroku (original commented out:
css_dir = 'tmp/stylesheets'
#css_dir = "public/stylesheets/compiled"
sass_dir = 'app/views/stylesheets'
environment = Compass::AppIntegration::Rails.env
Any help would be greatly appreciated.
I was actually just about to set up Compass with our Rails application, which is hosted on Heroku, so cheers for giving me an excuse to work through this. :)
The answer is simple:
Modify 'config/compass.rb':
project_type = :rails
project_path = Compass::AppIntegration::Rails.root
http_path = "/"
environment = Compass::AppIntegration::Rails.env
if environment == 'production'
css_dir = "tmp/stylesheets"
sass_dir = "app/views/stylesheets"
else
css_dir = "public/stylesheets"
sass_dir = "app/stylesheets"
end
Then modify 'config/initializers/compass.rb':
require 'compass'
require 'compass/app_integration/rails'
Compass::AppIntegration::Rails.initialize!
require 'fileutils'
FileUtils.mkdir_p(Rails.root.join("tmp", "stylesheets"))
environment = Compass::AppIntegration::Rails.env
if environment == 'production'
Compass::AppIntegration::Rails.initialize!
Rails.configuration.middleware.delete('Sass::Plugin::Rack')
Rails.configuration.middleware.insert_before('Rack::Sendfile', 'Sass::Plugin::Rack')
Rails.configuration.middleware.insert_before('Rack::Sendfile', 'Rack::Static',
:urls => ['/stylesheets'],
:root => "#{Rails.root}/tmp")
end
... and voila, you're good.
ok, I'm a big heroku and compass fan myself so i've been through this many times
Heroku's docs, whilst giving correct information, provide poor advice in this instance.
When using compass, the best thing to do, 99.999% of the time is turn it off in production mode.
This means that you compile your stylesheets on your development machine and then add them to your git repo before pushing to heroku.
You will suffer a reasonably sizeable performance hit if you allow compass to compile on the server.
So here's what I do:
You should have a config.ru file at the base of your app. Open it and add the following:
require 'sass/plugin/rack'
use Sass::Plugin::Rack
Sass::Plugin.options[:never_update] = true
You can then remove quite a lot of the code from your initializer (especially the part where you unload Sass::Plugin::Rack). Additionally you will want to remove the if statement from compass.rb in config folder
Think about it, why would you want Sass to compile a stylesheet on the server? It just eats up processing power. Hope this helps,
EDIT::
PS - I should add that you will need to run compass watch from the command line now in order to get your stylesheets to compile in your dev environment
The recommended Heroku configuration will also work locally.
Removed the second 'Compass::AppIntegration::Rails.initialize!' from config/initializers/compass.rb, you only need it once.
Ensure your scss files are in 'app/views/stylesheets'
On both local and production servers the stylesheets will be compiled to tmp/stylesheets, and a request to /stylesheets will resolve to tmp/stylesheest. No need for two separate configurations.

Multiple public folders, single rails installation

I have a rails application I would like to use for multiple sites, each with different designs.
I would like to change the rails installation /public directory to something else (dynamically eventually). However, I have run into a problem (bug?) changing directories...
In my application.rb file I change the paths.public path to something other than "public" (let's say "site_one"). Here is the code:
puts paths.public.paths
paths.public = "site_one"
puts paths.public.paths
The two "puts" commands are for debugging. Now run "rails s" and you will see:
/home/macklin/app/public
/home/macklin/app/site_one
This verifies the path is changed correctly. However, shortly afterward, rails throws the following error (let me know if you need the full trace):
Exiting
/usr/lib/ruby/gems/1.8/gems/railties-3.0.3/lib/rails/paths.rb:16:in `method_missing': undefined method `javascripts' for #<Rails::Paths::Path:0x7f422bd76f58> (NoMethodError) from /usr/lib/ruby/gems/1.8/gems/actionpack-3.0.3/lib/action_controller/railtie.rb:47
My guess is it cannot find the javascripts directory even though it is clearly sitting in the "site_one" folder.
Does anyone know why I am getting this?
I know this question is pretty old, but I think I found an answer for this in Rails 4.2.
You just simply have to put this line in your config/application.rb:
middleware.use ::ActionDispatch::Static, "#{Rails.root}/another_public_folder_name", index: 'index', headers: config.static_cache_control
This makes all files in /another_public_folder_name to be served by Rails.
This is the way Rails use to setup the standard /public folder. I found it checking the sources:
https://github.com/rails/rails/blob/52ce6ece8c8f74064bb64e0a0b1ddd83092718e1/railties/lib/rails/application/default_middleware_stack.rb#L24
Duh. Just add 2 more rules for stylesheets and javascripts (I guess they get wiped when you change the parent path)
paths.public.stylesheets = "site_one/stylesheets"
paths.public.javascripts = "site_one/javascripts"

Rails 3: how to load files in /lib?

I'm new to rails and making some sort of noob mistake: I frequently need to count the number of lines in a file, so I'm trying to monkey patch class File like this:
class File
def self.line_count( filename )
%x{wc -l #{filename}}.split.first.to_i
end
end
I saved this to /lib/file_util.rb. I thought that this was supposed to be auto-required, so that I could just use it, but that doesn't work:
$ rails console
>> File.line_count('Gemfile')
NoMethodError: undefined method `line_count' for File:Class
...
So I try to require it manually, no joy:
>> require '<myproj>/lib/file_util.rb' # same result with require 'file_util.rb'
=>nil
But it works if I require it within IRB:
$ irb
>> require '<myproj>/lib/file_util.rb'
=> true
>> File.line_count('Gemfile')
=> 22
I also tried to to add the require to config/application.rb:
...
Bundler.require(:default, Rails.env) if defined?(Bundler)
require 'file_util.rb'
module <myproj>
...
and I get:
$ rails console
<myproj>/config/application.rb:9:in `require': no such file to load -- file_util.rb (LoadError)
What am I doing wrong?
Ok, I seem to have mostly figured it out. Rails doesn't automatically require everything under /lib. It only auto loads when you try to use a new class name that matches a file name in lib. So if I define line_count in class FileUtil instead of File it automatically finds and loads 'file_util.rb'. But patching File and naming the patch file 'file.rb' doesn't work, since the File class is already defined, so Rails doesn't go looking for a definition.
My other problem was that I was trying to do the require too soon in the startup sequence, before Rails had a chance to enhance require to look in its directories. When I added "require 'file_util'" to config/environments/development.rb it works fine.
But this doesn't explain why I can't manually require the file from within rails console.
Monkeypatching classes can be done more easily by adding a file in config/initializers. All of those files are automatically loaded by Rails at startup.
You can call your initializer file anything you want. Try config/initializers/file.rb.