Change a RDoc template for generating Rails app documentation - ruby-on-rails

I have just added some documentation to my Rails 3.2.13 app. I can generate the documentation just fine (running RDoc 3.12.2) by using a rake task:
# lib/tasks/documentation.rake
Rake::Task["doc:app"].clear
Rake::Task["doc/app"].clear
Rake::Task["doc/app/index.html"].clear
namespace :doc do
RDoc::Task.new('app') do |rdoc|
rdoc.rdoc_dir = 'doc/app'
rdoc.generator = 'hanna'
rdoc.title = 'Stoffi Web App Documentation'
rdoc.main = 'doc/Overview'
rdoc.options << '--charset' << 'utf-8'
rdoc.rdoc_files.include('app/**/*.rb')
rdoc.rdoc_files.include('doc/*')
end
end
...and then running rake doc:app. But I really don't like the default look of the Hanna template. Is there a way to edit the CSS, perhaps by providing my own CSS file which will override the default one used in Hanna?
Thanks!

First of all find where your templates are located:
⮀ RDPATH=$(dirname $(gem which rdoc))
# ⇒ /home/am/.rvm/rubies/ruby-head/lib/ruby/2.1.0
Now copy the default template from there to the desired location (change /tmp to your project directory or like):
⮀ cp -r $RDPATH/rdoc/generator/template/darkfish /tmp/myniftytemplate
And, finally, let’s teach the rdoc:
class RDoc::Options
def template_dir_for template
"/tmp/#{template}"
end
end
RDoc::Task.new('app') do |rdoc|
rdoc.template = 'myniftytemplate'
…
end
That’s it. Hope it helps.

Related

Running webpacker:compile for a engine in my host app causes rails to abort

I have a rails engine/plugin in which i am trying to use webpacker using THIS article as a guide. So basically in my engine, i have the following code :-
lib/saddlebag.rb
require "saddlebag/engine"
module Saddlebag
# ...
class << self
def Webpacker
#Webpacker ||= ::Webpacker::Instance.new(
root_path: Saddlebag::Engine.root,
config_path: Saddlebag::Engine.root.join('config', 'webpacker.yml')
)
end
end
# ...
end
and in the lib/saddlebag/engine.rb file i have the following code :
module Saddlebag
class Engine < ::Rails::Engine
isolate_namespace Saddlebag
# use packs from saddlebag via Rack static
# file service, to enable webpacker to find them
# when running in the host application
config.app_middleware.use(
Rack::Static,
# note! this varies from the webpacker/engine documentation
urls: ["/saddlebag-packs"], root: Saddlebag::Engine.root.join("public")
)
initializer "webpacker.proxy" do |app|
insert_middleware = begin
Saddlebag.webpacker.config.dev_server.present?
rescue
nil
end
next unless insert_middleware
app.middleware.insert_before(
0, Webpacker::DevServerProxy, # "Webpacker::DevServerProxy" if Rails version < 5
ssl_verify_none: true,
webpacker: Saddlebag.webpacker
)
end
end
end
Also i have all of the files required by webpacker mainly :-
config/webpacker.yml and config/webpack/*.js files
bin/webpack and bin/webpack-dev-server files
package.json with required deps.
So the engine and my actually app are in sibling directories so:-
saddlebag
open-flights (main app)
in open flights i link saddlebag with the following line in the gem file :-
gem 'saddlebag', path: '../saddlebag'
Now when i run bin/rails saddlebag:webpacker:compile , i get the following error :-
rails aborted! Don't know how to build task
'saddlebag:webpacker:compile' (See the list of available tasks with
rails --tasks)
Why am i getting this error i have webpacker as a dependency in my saddlebag app. So not sure why this error still occures.
P.S. I found a similar guide for rails engine for enabling webpacker HERE (but uses docker)

How to use tailwind css gem in a rails 7 engine?

How to use tailwind in a rails engine? According to the documentation supplying a css argument to the Rails generator should work
Rails 7.0.2.2 engine generated using
rails plugin new tailtest --mountable --full -d postgresql --css tailwind
This generates the engine with Postgresql but does nothing with tailwind at all, and following manual installation instructions fail too.
Running, as per documentation, bundle add tailwindcss-rails adds tailwind to the gemfile rather than the engines tailtest.gemspec
So after adding the dependency to the gemspec
spec.add_dependency "tailwindcss-rails", "~> 2.0"
and running bundle install does install the engine however the rest of the manual installation fails
then adding the require to lib/engine.rb
require "tailwindcss-rails"
module Tailtest
class Engine < ::Rails::Engine
isolate_namespace Tailtest
end
end
then running the install process fails
rails tailwindcss:install
Resolving dependencies...
rails aborted!
Don't know how to build task 'tailwindcss:install' (See the list of available tasks with `rails --tasks`)
Did you mean? app:tailwindcss:install
Obviously the app:tailwindcss:install command fails too.
So I am probably missing an initializer of some sort in the engine.rb file but no idea on what it should be.
It is the same idea as How to set up importmap-rails in Rails 7 engine?. We don't need to use the install task. Even if you're able to run it, it's not helpful in the engine (see the end of the answer for explanation).
Also rails plugin new doesn't have a --css option. To see available options: rails plugin new -h.
Update engine's gemspec file:
# my_engine/my_engine.gemspec
spec.add_dependency "tailwindcss-rails"
Update engine.rb:
# my_engine/lib/my_engine/engine.rb
module MyEngine
class Engine < ::Rails::Engine
isolate_namespace MyEngine
# NOTE: add engine manifest to precompile assets in production, if you don't have this yet.
initializer "my-engine.assets" do |app|
app.config.assets.precompile += %w[my_engine_manifest]
end
end
end
Update assets manifest:
# my_engine/app/assets/config/my_engine_manifest.js
//= link_tree ../builds/ .css
Update engine's layout:
# my_engine/app/views/layouts/my_engine/application.html.erb
<!DOCTYPE html>
<html>
<head>
<%#
NOTE: make sure this name doesn't clash with anything in the main app.
think of it as `require` and `$LOAD_PATH`,
but instead it is `stylesheet_link_tag` and `manifest.js`.
%>
<%= stylesheet_link_tag "my_engine", "data-turbo-track": "reload" %>
</head>
<body> <%= yield %> </body>
</html>
bundle show command will give us the path where the gem is installed, so we can copy a few files:
$ bundle show tailwindcss-rails
/home/alex/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/tailwindcss-rails-2.0.8-x86_64-linux
Copy tailwind.config.js file from tailwindcss-rails:
$ cp $(bundle show tailwindcss-rails)/lib/install/tailwind.config.js config/tailwind.config.js
Copy application.tailwind.css file into any directory to fit your setup:
$ cp $(bundle show tailwindcss-rails)/lib/install/application.tailwind.css app/assets/stylesheets/application.tailwind.css
Because tailwindcss-rails uses standalone executable, we don't need node or rails to compile the stylesheets. We just need to get to the executable itself.
Executable is located here https://github.com/rails/tailwindcss-rails/tree/v2.0.8/exe/. Instead of running the build task https://github.com/rails/tailwindcss-rails/blob/v2.0.8/lib/tasks/build.rake we can just call the executable directly.
$ $(bundle show tailwindcss-rails)/exe/tailwindcss -i app/assets/stylesheets/application.tailwind.css -o app/assets/builds/my_engine.css -c config/tailwind.config.js --minify
Use -w option to start watch mode.
$ $(bundle show tailwindcss-rails)/exe/tailwindcss -i app/assets/stylesheets/application.tailwind.css -o app/assets/builds/my_engine.css -c config/tailwind.config.js --minify -w
The output file should match the name in stylesheet_link_tag "my_engine".
Now that you have a plain my_engine.css file, do with it what you want. Use it in the layout, require it from the main app application.css. The usual rails asset pipeline rules apply.
If you want to put all that into a task, use Engine.root to get the paths.
# my_engine/lib/tasks/my_engine.rake
task :tailwind_engine_watch do
require "tailwindcss-rails"
# NOTE: tailwindcss-rails is an engine
system "#{Tailwindcss::Engine.root.join("exe/tailwindcss")} \
-i #{MyEngine::Engine.root.join("app/assets/stylesheets/application.tailwind.css")} \
-o #{MyEngine::Engine.root.join("app/assets/builds/my_engine.css")} \
-c #{MyEngine::Engine.root.join("config/tailwind.config.js")} \
--minify -w"
end
From the engine directory:
$ bin/rails app:tailwind_engine_watch
+ /home/alex/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/tailwindcss-rails-2.0.8-x86_64-linux/exe/x86_64-linux/tailwindcss -i /home/alex/code/stackoverflow/my_engine/app/assets/stylesheets/application.tailwind.css -o /home/alex/code/stackoverflow/my_engine/app/assets/builds/my_engine.css -c /home/alex/code/stackoverflow/my_engine/config/tailwind.config.js --minify -w
Rebuilding...
Done in 549ms.
Make your own install task if you have a lot of engines to set up:
desc "Install tailwindcss into our engine"
task :tailwind_engine_install do
require "tailwindcss-rails"
# NOTE: use default app template, which will fail to modify layout, manifest,
# and the last command that compiles the initial `tailwind.css`.
# It will also add `bin/dev` and `Procfile.dev` which we don't need.
# Basically, it's useless in the engine as it is.
template = Tailwindcss::Engine.root.join("lib/install/tailwindcss.rb")
# TODO: better to copy the template from
# https://github.com/rails/tailwindcss-rails/blob/v2.0.8/lib/install/tailwindcss.rb
# and customize it
# template = MyEngine::Engine.root("lib/install/tailwindcss.rb")
require "rails/generators"
require "rails/generators/rails/app/app_generator"
# NOTE: because the app template uses `Rails.root` it will run the install
# on our engine's dummy app. Just override `Rails.root` with our engine
# root to run install in the engine directory.
Rails.configuration.root = MyEngine::Engine.root
generator = Rails::Generators::AppGenerator.new [Rails.root], {}, { destination_root: Rails.root }
generator.apply template
end
Install task reference:
https://github.com/rails/rails/blob/v7.0.2.4/railties/lib/rails/tasks/framework.rake#L8
https://github.com/rails/tailwindcss-rails/blob/v2.0.8/lib/tasks/install.rake
Watch task reference:
https://github.com/rails/tailwindcss-rails/blob/v2.0.8/lib/tasks/build.rake#L10
Update How to merge two tailwinds.
Above setup assumes the engine is its own separate thing, like admin backend, it has its own routes, templates, and styles. If an engine functionality is meant to be mixed with the main app, like a view_component collection, then tailwind styles will override each other. In this case isolating engine styles with a prefix could work:
https://tailwindcss.com/docs/configuration#prefix
The reason that tailwind styles don't mix is because most of the selectors have the same specificity and the order is very important.
So here is an example. Main app with an engine, both using tailwind, both compile styles separately, tailwind configs are only watching one file from the engine and one from the main app, only using #tailwind utilities; directive:
Engine template, that we want to use in the main app, should work fine:
<!-- blep/app/views/blep/_partial.html.erb -->
<div class="bg-red-500 sm:bg-blue-500"> red never-blue </div>
But when rendered in the main app it never turns blue. Here is the demonstration set up:
<!-- app/views/home/index.html.erb -->
<%= stylesheet_link_tag "blep", "data-turbo-track": "reload" %>
<%= stylesheet_link_tag "tailwind", "data-turbo-track": "reload" %>
<!-- output generated css in the same order as above link tags -->
<% require "open-uri" %>
<b>Engine css</b>
<pre><%= URI.open(asset_url("blep")).read %></pre>
<b>Main app css</b>
<pre><%= URI.open(asset_url("tailwind")).read %></pre>
<div class="bg-red-500"> red </div> <!-- this generates another bg-red-500 -->
<br>
<%= render "blep/partial" %>
And it looks like this:
/* Engine css */
.bg-red-500 {
--tw-bg-opacity: 1;
background-color: rgb(239 68 68 / var(--tw-bg-opacity))
}
#media (min-width: 640px) {
.sm\:bg-blue-500 {
--tw-bg-opacity: 1;
background-color: rgb(59 130 246 / var(--tw-bg-opacity))
}
}
/* Main app css */
.bg-red-500 {
--tw-bg-opacity: 1;
background-color: rgb(239 68 68 / var(--tw-bg-opacity))
}
<div class="bg-red-500"> red </div>
<br>
<div class="bg-red-500 sm:bg-blue-500"> red never-blue </div>
^ you can hit run and click "full page". Main app bg-red-500 selector is last so it overrides engines sm:bg-blue-500 selector, media queries don't add to specificity score. It's the same reason you can't override, say, mt-1 with m-2, margin top comes later in the stylesheet. This is why #layer directives are important.
The only way around this is to watch the engine directory when running tailwind in the main app, so that styles are compiled together and in the correct order. Which means you don't really need tailwind in the engine:
module.exports = {
content: [
"./app/**/*",
"/just/type/the/path/to/engine/views",
"/or/see/updated/task/below",
],
}
Other ways I tried, like running 6 tailwind commands for each layer for main app and engine, so that I can put them in order, better but was still out of order a bit and duplicated. Or doing an #import and somehow letting postcss-import know where to look for engine styles (I don't know, I just symlinked it into node_modules to test), but this still required tailwind to watch engine files.
I did some more digging, tailwind cli has a --content option, which will override content from tailwind.config.js. We can use it to setup a new task:
namespace :tailwindcss do
desc "Build your Tailwind CSS + Engine"
task :watch do |_, args|
# NOTE: there have been some updates, there is a whole Commands class now
# lets copy paste and modify. (debug = no --minify)
command = Tailwindcss::Commands.watch_command(debug: true, poll: false)
# --content /path/to/app/**/*,/path/to/engine/**/*
command << "--content"
command << [
Rails.root.join("app/views/home/*"),
Blep::Engine.root.join("app/views/**/*.erb")
].join(",")
p command
system(*command)
end
# same for build, just call `compile_command`
# task :build do |_, args|
# command = Tailwindcss::Commands.compile_command(debug: false)
# ...
end
https://github.com/rails/tailwindcss-rails/blob/v2.0.21/lib/tasks/build.rake#L11
That answer by Alex is really good, i wish i had it when starting out. (But i didn't even have the question to google)
Just want to add two things:
1- a small simplification. I just made a script to run tailwind in the engine
#!/usr/bin/env sh
# Since tailwind does not install into the engine, this will
# watch and recompile during development
# tailwindcss executable must exist (by bundling tailwindcss-rails eg)
tailwindcss -i app/assets/stylesheets/my_engine.tailwind.css \
-o app/assets/stylesheets/my_engine/my_engine.css \
-c config/tailwind.config.js \
-w
2- For usage in an app, that obviously also uses tailwind, i was struggling, since the two generated css's were biting each other and i could not get both styles to work in one page. Always one or the other (app or engine) was not styled right. Until i got the app's tailwind to pick up the engines classes.
Like so:
Add to the app's tailwind.config.js: before the module
const execSync = require('child_process').execSync;
const output = execSync('bundle show my_engine', { encoding: 'utf-8' });
And then inside the content as last line
output.trim() + '/app/**/*.{erb,haml,html,rb}'
Then just include the apps generated tailwind css in the layout, like the installer will. Don't include the engines stylesheet in the layout, or add it to the asset

How to set up importmap-rails in Rails 7 engine?

I have opened an issue in the importmap-rails gem github repository here about this but thought I'd throw the question out here in case anyone might have a workaround
This is what I have discovered so far
A new engine with Rails 7 alpha 2 or Rails 7.0, generated using rails plugin new custom_page --mountable --full generates a new engine that includes the importmap-rails gem in the bundled gems but there is no ability to use it. Adding spec.add_dependency 'importmap-rails' to the enginename.gemspec makes no difference, nor does adding a require importmap-rails to engine.rb. There is no importmap executable in the bin directory.
A call to bundle info importmap-rails
Produces a promising result showing that the gem is installed by default
* importmap-rails (0.8.1)
Summary: Use ESM with importmap to manage modern JavaScript in Rails without transpiling or bundling.
Homepage: https://github.com/rails/importmap-rails
Source Code: https://github.com/rails/importmap-rails
Path: /home/jamie/.rvm/gems/ruby-3.0.0#custom_page/gems/importmap-rails-0.8.1
A call to rails --tasks shows
rails app:importmap:install # Setup Importmap for the app
But I believe this is coming from the test application generated by the --full option rather than being available to the rails command for the engine.
I was expecting to see the same without app: prefix
A call to this task resolves to a template error as shown
rails app:importmap:install
Don't know how to build task 'app:template' (See the list of available
tasks with rails --tasks) Did you mean? app:tmp:create
If there is a workaround solution to this I'd be grateful to hear it and I'm sure others will too. The reason for me wanting this is that I totally failed to introduced webpacker in a rails 6.1.4 engine and I was hoping this was going to be my, much improved, solution
You don't need to use the install task to set up importmaps. All it does is a few copy paste operations and it doesn't really help with the engine set up anyway.
Add importmaps to engine's gemspec file:
# my_engine/my_engine.gemspec
spec.add_dependency "importmap-rails"
Update engine.rb:
# my_engine/lib/my_engine/engine.rb
require "importmap-rails"
module MyEngine
class Engine < ::Rails::Engine
isolate_namespace MyEngine
initializer "my-engine.importmap", before: "importmap" do |app|
# NOTE: this will add pins from this engine to the main app
# https://github.com/rails/importmap-rails#composing-import-maps
app.config.importmap.paths << root.join("config/importmap.rb")
# NOTE: something about cache; I did not look into it.
# https://github.com/rails/importmap-rails#sweeping-the-cache-in-development-and-test
app.config.importmap.cache_sweepers << root.join("app/assets/javascripts")
end
# NOTE: add engine manifest to precompile assets in production
initializer "my-engine.assets" do |app|
app.config.assets.precompile += %w[my_engine_manifest]
end
end
end
Update assets manifest:
# my_engine/app/assets/config/my_engine_manifest.js
//= link_tree ../javascripts/my_engine .js
Add javascript entry point for our engine, if needed. Pins will be available without this file.
# my_engine/app/assets/javascripts/my_engine/application.js
// do some javascript
document.querySelector("h1").innerText = "hi, i'm your engine";
console.log("hi, again");
Update engine's layout:
# my_engine/app/views/layouts/my_engine/application.html.erb
<!DOCTYPE html>
<html>
<head>
<!--
NOTE: This loads/imports main app `application.js` and all the pins from
the main app and from the engine (because we set it up in the engine.rb).
-->
<%= javascript_importmap_tags %>
<!--
NOTE: To add engine's javascript functionality we have to load the
entrypoint here or `import` it in the main app `application.js`
-->
<%= javascript_import_module_tag "my_engine/application" %>
</head>
<body> <%= yield %> </body>
</html>
Create importmap.rb and pin my_engine/application, this name has to match with javascript_import_module_tag. It cannot clash with any other name in the main app, so you can't just use application:
# my_engine/config/importmap.rb
# NOTE: this pin works because `my_engine/app/assets/javascripts
# is in the `Rails.application.config.assets.paths`
pin "my_engine/application"
Some extras to test the setup:
# config/routes.rb
Rails.application.routes.draw do
mount MyEngine::Engine => "/"
end
# my_engine/config/routes.rb
MyEngine::Engine.routes.draw do
get "home", to: "homes#index"
end
# my_engine/app/controllers/my_engine/homes_controller.rb
module MyEngine
class HomesController < ApplicationController
def index; end
end
end
# my_engine/app/views/my_engine/homes/index.html.erb
<h1>Home</h1>
At this point you should have this in your rendered layout's <head> tag, among other things:
<script type="importmap" data-turbo-track="reload">{
"imports": {
"application": "/assets/application-66ce7505c61e3e4910ff16e7c220e1fbfb39251cd82e4bab8d325b3aae987cf9.js",
"my_engine/application": "/assets/my_engine/application-31ce493e8376b4c20703a50f38d419ae309ffe410b7ab7fec47440e02eef08a8.js",
}
}</script>
<script type="module">import "application"</script>
<script type="module">import "my_engine/application"</script>
H1 tag should change to <h1>hi, i'm your engine</h1> on reload.
Additional importmaps can be added manually with https://generator.jspm.io/.
For bonus points, bin/importmap can be customized to work inside the engine. Create a new importmap file inside bin directory.
# my_engine/bin/importmap
#!/usr/bin/env ruby
# NOTE: don't forget to `chmod u+x bin/importmap` to make it executable.
# make sure we are loading the correct versions of things
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
# NOTE: importmap requires some rails goodness that we don't have in the engine,
# because we don't have `config/application.rb` that loads the environment.
require "rails"
# importmap-rails is not loaded automatically
require "importmap-rails"
# the actual command runner
require "importmap/commands"
Run from inside the engine directory:
$ bin/importmap pin react
Pinning "react" to https://ga.jspm.io/npm:react#18.1.0/index.js
$ cat config/importmap.rb
pin "my_engine/application"
pin "react", to: "https://ga.jspm.io/npm:react#18.1.0/index.js"
I haven't tested it too much, so any feedback would be welcome. Restart the server if something doesn't show up, I don't know how reloading behaves with all this.
I fall back to the old school Javascript include in the html.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.js"></script>
Well it definitely works on all browser instead of figuring out if the browser supports the feature that I might use later.
I have full control which page to put too... but that might not be what you want...

`rake notes` should scan haml

According to the guides:
... is done in files with extension .builder, .rb, .erb, .haml and .slim for both default and custom annotations.
But it isn't working, even when manually configured:
$ rails -v
Rails 4.2.3
$ grep -r annotations config/environments/development.rb
config/environments/development.rb: config.annotations.register_extensions('haml') { |a| /#\s*(#{a}):?\s*(.*)$/ }
$ grep -r TODO app/views
app/views/orders/show.html.haml: -# TODO: Add link
$ rake notes
app/models/order.rb:
* [12] [TODO] Refactor
Anyone know how to get it working?
Short answer
Add this line
SourceAnnotationExtractor::Annotation.register_extensions("haml") { |tag| /(?:\/\/|#)\s*(#{tag}):?\s*(.*)$/ }
at the end of Rakefile inside of your Rails app.
Longer answer
rake notes
is defined there :
https://github.com/rails/rails/blob/master/railties/lib/rails/tasks/annotations.rake
task :notes do
SourceAnnotationExtractor.enumerate "OPTIMIZE|FIXME|TODO", tag: true
end
this task doesn't depend on :environment, so for example, no code inside config/initializers/ or config/environment will be executed for this task. Putting any configuration there won't have any effect for rake notes.
Only config/application.rb will be required, from Rakefile.
https://github.com/rails/rails/blob/master/railties/lib/rails/source_annotation_extractor.rb tells us that we can define a new file extension for Annotations like this :
SourceAnnotationExtractor::Annotation.register_extensions("css", "scss", "sass", "less", "js") { |tag| /\/\/\s*(#{tag}):?\s*(.*)$/ }
so adding this line inside Rakefile or config/application.rb will define the new annotation before the notes task is executed.
I'm not sure why it doesn't work out of the box for haml, since it's defined in haml-rails.
For the time being, with Rails 4.2.2 and haml-rails 0.9.0, the short answer above should do.
Put the following into config/initializers/ :
Rails.application.config.annotations.tap do |notes|
notes.register_extensions('haml') { |annotation| %r(#\s*(#{annotation}):?\s*(.*?)$) }
end
for more details you can refer this

Paperclip File Not Found Error

I just switched from a paperclip rails plugin to a paperclip gem. The project is a rails 2.3 application and I am using paperclip 2.7.2 gem.
I am getting the following odd error:
identify: unable to open image `file': No such file or directory # error/blob.c/OpenBlob/2617.
identify: no decode delegate for this image format `file' # error/constitute.c/ReadImage/544.
Seems like paperclip is looking for a file called 'file' but I am not sure why. I didn't change any of the code we had before. It used to work, all I did was upgrade to a newer version and use a gem over a plugin.
Any ideas?
Update
It to be a bug in paper clip where it does not parse the content of the command properly. I dug deep into the paperclip source to find:
def run(cmd, arguments = "", local_options = {})
if options[:image_magick_path]
Paperclip.log("[DEPRECATION] :image_magick_path is deprecated and will be removed. Use :command_path instead")
end
command_path = options[:command_path] || options[:image_magick_path]
Cocaine::CommandLine.path = [Cocaine::CommandLine.path, command_path].flatten.compact.uniq
local_options = local_options.merge(:logger => logger) if logging? && (options[:log_command] || local_options[:log_command])
Cocaine::CommandLine.new(cmd, arguments, local_options).run
end
and
# Uses ImageMagick to determing the dimensions of a file, passed in as either a
# File or path.
# NOTE: (race cond) Do not reassign the 'file' variable inside this method as it is likely to be
# a Tempfile object, which would be eligible for file deletion when no longer referenced.
def self.from_file file
file_path = file.respond_to?(:path) ? file.path : file
raise(Paperclip::NotIdentifiedByImageMagickError.new("Cannot find the geometry of a file with a blank name")) if file_path.blank?
geometry = begin
Paperclip.run("identify", "-format %wx%h :file", :file => "#{file_path}[0]")
rescue Cocaine::ExitStatusError
""
rescue Cocaine::CommandNotFoundError => e
raise Paperclip::CommandNotFoundError.new("Could not run the `identify` command. Please install ImageMagick.")
end
parse(geometry) ||
raise(NotIdentifiedByImageMagickError.new("#{file_path} is not recognized by the 'identify' command."))
end
The Paperclip.run command fails to replace the :file placeholder for some reason. I verified this by running the following on the commandline:
identify :file
Monkey patching the replacement by hand yields other errors where a similar thing happens.
Ok I managed to solve it.
It was a problem with Cocaine. Seems paperclip has a dependency on cocaine that only says it must be Cociane > 0.02. The latest version of Cocaine 0.4.2 (at the time of this writing) has a new API which is not backward compatible. You need to downgrade to Cocaine 0.3.2.
Simply put this in your Gemfile before paperclip:
gem "cocaine", "0.3.2"

Resources