paperclip_database 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +54 -0
- data/.rspec +1 -0
- data/Appraisals +14 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +102 -0
- data/LICENSE.txt +26 -0
- data/README.rdoc +19 -0
- data/Rakefile +41 -0
- data/features/basic_integration.feature +29 -0
- data/features/step_definitions/html_steps.rb +15 -0
- data/features/step_definitions/paperclip_database_steps.rb +0 -0
- data/features/step_definitions/rails_steps.rb +193 -0
- data/features/step_definitions/web_steps.rb +209 -0
- data/features/support/env.rb +15 -0
- data/features/support/fakeweb.rb +3 -0
- data/features/support/paths.rb +28 -0
- data/features/support/rails.rb +46 -0
- data/features/support/selectors.rb +19 -0
- data/gemfiles/rails2.gemfile +8 -0
- data/gemfiles/rails3.gemfile +8 -0
- data/gemfiles/rails3_1.gemfile +8 -0
- data/generators/paperclip_database/USAGE +5 -0
- data/generators/paperclip_database/paperclip_database_generator.rb +28 -0
- data/generators/paperclip_database/templates/paperclip_database_migration.rb.erb +17 -0
- data/generators/templates/paperclip_database_migration.rb.erb +17 -0
- data/lib/generators/paperclip_database/USAGE +8 -0
- data/lib/generators/paperclip_database/paperclip_database_generator.rb +33 -0
- data/lib/generators/paperclip_database/templates/paperclip_database_migration.rb.erb +17 -0
- data/lib/paperclip/storage/database.rb +198 -0
- data/lib/paperclip_database/version.rb +3 -0
- data/lib/paperclip_database.rb +4 -0
- data/paperclip_database.gemspec +37 -0
- data/rails/init.rb +3 -0
- data/spec/paperclip_database_spec.rb +7 -0
- data/spec/spec_helper.rb +12 -0
- data/test/fixtures/5k.png +0 -0
- metadata +199 -0
@@ -0,0 +1,209 @@
|
|
1
|
+
# TL;DR: YOU SHOULD DELETE THIS FILE
|
2
|
+
#
|
3
|
+
# This file was generated by Cucumber-Rails and is only here to get you a head start
|
4
|
+
# These step definitions are thin wrappers around the Capybara/Webrat API that lets you
|
5
|
+
# visit pages, interact with widgets and make assertions about page content.
|
6
|
+
#
|
7
|
+
# If you use these step definitions as basis for your features you will quickly end up
|
8
|
+
# with features that are:
|
9
|
+
#
|
10
|
+
# * Hard to maintain
|
11
|
+
# * Verbose to read
|
12
|
+
#
|
13
|
+
# A much better approach is to write your own higher level step definitions, following
|
14
|
+
# the advice in the following blog posts:
|
15
|
+
#
|
16
|
+
# * http://benmabey.com/2008/05/19/imperative-vs-declarative-scenarios-in-user-stories.html
|
17
|
+
# * http://dannorth.net/2011/01/31/whose-domain-is-it-anyway/
|
18
|
+
# * http://elabs.se/blog/15-you-re-cuking-it-wrong
|
19
|
+
#
|
20
|
+
|
21
|
+
|
22
|
+
require 'uri'
|
23
|
+
require 'cgi'
|
24
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "paths"))
|
25
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "selectors"))
|
26
|
+
|
27
|
+
module WithinHelpers
|
28
|
+
def with_scope(locator)
|
29
|
+
locator ? within(*selector_for(locator)) { yield } : yield
|
30
|
+
end
|
31
|
+
end
|
32
|
+
World(WithinHelpers)
|
33
|
+
|
34
|
+
# Single-line step scoper
|
35
|
+
When /^(.*) within (.*[^:])$/ do |step, parent|
|
36
|
+
with_scope(parent) { When step }
|
37
|
+
end
|
38
|
+
|
39
|
+
# Multi-line step scoper
|
40
|
+
When /^(.*) within (.*[^:]):$/ do |step, parent, table_or_string|
|
41
|
+
with_scope(parent) { When "#{step}:", table_or_string }
|
42
|
+
end
|
43
|
+
|
44
|
+
Given /^(?:|I )am on (.+)$/ do |page_name|
|
45
|
+
visit path_to(page_name)
|
46
|
+
end
|
47
|
+
|
48
|
+
When /^(?:|I )go to (.+)$/ do |page_name|
|
49
|
+
visit path_to(page_name)
|
50
|
+
end
|
51
|
+
|
52
|
+
When /^(?:|I )press "([^"]*)"$/ do |button|
|
53
|
+
click_button(button)
|
54
|
+
end
|
55
|
+
|
56
|
+
When /^(?:|I )follow "([^"]*)"$/ do |link|
|
57
|
+
click_link(link)
|
58
|
+
end
|
59
|
+
|
60
|
+
When /^(?:|I )fill in "([^"]*)" with "([^"]*)"$/ do |field, value|
|
61
|
+
fill_in(field, :with => value)
|
62
|
+
end
|
63
|
+
|
64
|
+
When /^(?:|I )fill in "([^"]*)" for "([^"]*)"$/ do |value, field|
|
65
|
+
fill_in(field, :with => value)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Use this to fill in an entire form with data from a table. Example:
|
69
|
+
#
|
70
|
+
# When I fill in the following:
|
71
|
+
# | Account Number | 5002 |
|
72
|
+
# | Expiry date | 2009-11-01 |
|
73
|
+
# | Note | Nice guy |
|
74
|
+
# | Wants Email? | |
|
75
|
+
#
|
76
|
+
# TODO: Add support for checkbox, select og option
|
77
|
+
# based on naming conventions.
|
78
|
+
#
|
79
|
+
When /^(?:|I )fill in the following:$/ do |fields|
|
80
|
+
fields.rows_hash.each do |name, value|
|
81
|
+
When %{I fill in "#{name}" with "#{value}"}
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
When /^(?:|I )select "([^"]*)" from "([^"]*)"$/ do |value, field|
|
86
|
+
select(value, :from => field)
|
87
|
+
end
|
88
|
+
|
89
|
+
When /^(?:|I )check "([^"]*)"$/ do |field|
|
90
|
+
check(field)
|
91
|
+
end
|
92
|
+
|
93
|
+
When /^(?:|I )uncheck "([^"]*)"$/ do |field|
|
94
|
+
uncheck(field)
|
95
|
+
end
|
96
|
+
|
97
|
+
When /^(?:|I )choose "([^"]*)"$/ do |field|
|
98
|
+
choose(field)
|
99
|
+
end
|
100
|
+
|
101
|
+
When /^(?:|I )attach the file "([^"]*)" to "([^"]*)"$/ do |path, field|
|
102
|
+
attach_file(field, File.expand_path(path))
|
103
|
+
end
|
104
|
+
|
105
|
+
Then /^(?:|I )should see "([^"]*)"$/ do |text|
|
106
|
+
if page.respond_to? :should
|
107
|
+
page.should have_content(text)
|
108
|
+
else
|
109
|
+
assert page.has_content?(text)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
Then /^(?:|I )should see \/([^\/]*)\/$/ do |regexp|
|
114
|
+
regexp = Regexp.new(regexp)
|
115
|
+
|
116
|
+
if page.respond_to? :should
|
117
|
+
page.should have_xpath('//*', :text => regexp)
|
118
|
+
else
|
119
|
+
assert page.has_xpath?('//*', :text => regexp)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
Then /^(?:|I )should not see "([^"]*)"$/ do |text|
|
124
|
+
if page.respond_to? :should
|
125
|
+
page.should have_no_content(text)
|
126
|
+
else
|
127
|
+
assert page.has_no_content?(text)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
Then /^(?:|I )should not see \/([^\/]*)\/$/ do |regexp|
|
132
|
+
regexp = Regexp.new(regexp)
|
133
|
+
|
134
|
+
if page.respond_to? :should
|
135
|
+
page.should have_no_xpath('//*', :text => regexp)
|
136
|
+
else
|
137
|
+
assert page.has_no_xpath?('//*', :text => regexp)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
Then /^the "([^"]*)" field(?: within (.*))? should contain "([^"]*)"$/ do |field, parent, value|
|
142
|
+
with_scope(parent) do
|
143
|
+
field = find_field(field)
|
144
|
+
if field.value.respond_to? :should
|
145
|
+
field.value.should =~ /#{value}/
|
146
|
+
else
|
147
|
+
assert_match(/#{value}/, field.value)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
Then /^the "([^"]*)" field(?: within (.*))? should not contain "([^"]*)"$/ do |field, parent, value|
|
153
|
+
with_scope(parent) do
|
154
|
+
field = find_field(field)
|
155
|
+
if field.value.respond_to? :should_not
|
156
|
+
field.value.should_not =~ /#{value}/
|
157
|
+
else
|
158
|
+
assert_no_match(/#{value}/, field.value)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
Then /^the "([^"]*)" checkbox(?: within (.*))? should be checked$/ do |label, parent|
|
164
|
+
with_scope(parent) do
|
165
|
+
field_checked = find_field(label)['checked']
|
166
|
+
if field_checked.respond_to? :should
|
167
|
+
field_checked.should be_true
|
168
|
+
else
|
169
|
+
assert field_checked
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
Then /^the "([^"]*)" checkbox(?: within (.*))? should not be checked$/ do |label, parent|
|
175
|
+
with_scope(parent) do
|
176
|
+
field_checked = find_field(label)['checked']
|
177
|
+
if field_checked.respond_to? :should
|
178
|
+
field_checked.should be_false
|
179
|
+
else
|
180
|
+
assert !field_checked
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
Then /^(?:|I )should be on (.+)$/ do |page_name|
|
186
|
+
current_path = URI.parse(current_url).path
|
187
|
+
if current_path.respond_to? :should
|
188
|
+
current_path.should == path_to(page_name)
|
189
|
+
else
|
190
|
+
assert_equal path_to(page_name), current_path
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
Then /^(?:|I )should have the following query string:$/ do |expected_pairs|
|
195
|
+
query = URI.parse(current_url).query
|
196
|
+
actual_params = query ? CGI.parse(query) : {}
|
197
|
+
expected_params = {}
|
198
|
+
expected_pairs.rows_hash.each_pair{|k,v| expected_params[k] = v.split(',')}
|
199
|
+
|
200
|
+
if actual_params.respond_to? :should
|
201
|
+
actual_params.should == expected_params
|
202
|
+
else
|
203
|
+
assert_equal expected_params, actual_params
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
Then /^show me the page$/ do
|
208
|
+
save_and_open_page
|
209
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#require 'bundler'
|
2
|
+
begin
|
3
|
+
Bundler.setup(:default, :development)
|
4
|
+
rescue Bundler::BundlerError => e
|
5
|
+
$stderr.puts e.message
|
6
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
7
|
+
exit e.status_code
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'aruba/cucumber'
|
11
|
+
require 'capybara/cucumber'
|
12
|
+
|
13
|
+
Before do
|
14
|
+
@aruba_timeout_seconds = 120
|
15
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module NavigationHelpers
|
2
|
+
# Maps a name to a path. Used by the
|
3
|
+
#
|
4
|
+
# When /^I go to (.+)$/ do |page_name|
|
5
|
+
#
|
6
|
+
# step definition in web_steps.rb
|
7
|
+
#
|
8
|
+
def path_to(page_name)
|
9
|
+
case page_name
|
10
|
+
|
11
|
+
when /the home\s?page/
|
12
|
+
'/'
|
13
|
+
when /the new user page/
|
14
|
+
'/users/new'
|
15
|
+
else
|
16
|
+
begin
|
17
|
+
page_name =~ /the (.*) page/
|
18
|
+
path_components = $1.split(/\s+/)
|
19
|
+
self.send(path_components.push('path').join('_').to_sym)
|
20
|
+
rescue Object => e
|
21
|
+
raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
|
22
|
+
"Now, go and add a mapping in #{__FILE__}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
World(NavigationHelpers)
|
@@ -0,0 +1,46 @@
|
|
1
|
+
PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..')).freeze
|
2
|
+
APP_NAME = 'testapp'.freeze
|
3
|
+
BUNDLE_ENV_VARS = %w(RUBYOPT BUNDLE_PATH BUNDLE_BIN_PATH BUNDLE_GEMFILE)
|
4
|
+
ORIGINAL_BUNDLE_VARS = Hash[ENV.select{ |key,value| BUNDLE_ENV_VARS.include?(key) }]
|
5
|
+
|
6
|
+
ENV['RAILS_ENV'] = 'test'
|
7
|
+
|
8
|
+
Before do
|
9
|
+
ENV['BUNDLE_GEMFILE'] = File.join(Dir.pwd, ENV['BUNDLE_GEMFILE']) unless ENV['BUNDLE_GEMFILE'].start_with?(Dir.pwd)
|
10
|
+
@framework_version = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
After do
|
14
|
+
ORIGINAL_BUNDLE_VARS.each_pair do |key, value|
|
15
|
+
ENV[key] = value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
When /^I reset Bundler environment variable$/ do
|
20
|
+
BUNDLE_ENV_VARS.each do |key|
|
21
|
+
ENV[key] = nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module RailsCommandHelpers
|
26
|
+
def framework_version?(version_string)
|
27
|
+
framework_version =~ /^#{version_string}/
|
28
|
+
end
|
29
|
+
|
30
|
+
def framework_version
|
31
|
+
@framework_version ||= `rails -v`[/^Rails (.+)$/, 1]
|
32
|
+
end
|
33
|
+
|
34
|
+
def new_application_command
|
35
|
+
framework_version?("3") ? "rails new" : "rails"
|
36
|
+
end
|
37
|
+
|
38
|
+
def generator_command
|
39
|
+
framework_version?("3") ? "script/rails generate" : "script/generate"
|
40
|
+
end
|
41
|
+
|
42
|
+
def runner_command
|
43
|
+
framework_version?("3") ? "script/rails runner" : "script/runner"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
World(RailsCommandHelpers)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module HtmlSelectorsHelpers
|
2
|
+
# Maps a name to a selector. Used primarily by the
|
3
|
+
#
|
4
|
+
# When /^(.+) within (.+)$/ do |step, scope|
|
5
|
+
#
|
6
|
+
# step definitions in web_steps.rb
|
7
|
+
#
|
8
|
+
def selector_for(locator)
|
9
|
+
case locator
|
10
|
+
when "the page"
|
11
|
+
"html > body"
|
12
|
+
else
|
13
|
+
raise "Can't find mapping from \"#{locator}\" to a selector.\n" +
|
14
|
+
"Now, go and add a mapping in #{__FILE__}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
World(HtmlSelectorsHelpers)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class PaperclipDatabaseGenerator < Rails::Generator::NamedBase
|
2
|
+
attr_accessor :attachments, :migration_name
|
3
|
+
|
4
|
+
def initialize(args, options = {})
|
5
|
+
super
|
6
|
+
@class_name, @attachments = args[0], args[1..-1]
|
7
|
+
end
|
8
|
+
|
9
|
+
def manifest
|
10
|
+
file_name = generate_file_name
|
11
|
+
@migration_name = file_name.camelize
|
12
|
+
record do |m|
|
13
|
+
m.migration_template "paperclip_database_migration.rb.erb",
|
14
|
+
File.join('db', 'migrate'),
|
15
|
+
:migration_file_name => file_name
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def generate_file_name
|
22
|
+
debugger
|
23
|
+
names = attachments.map{|a| "#{class_name.underscore}_#{a.pluralize}" }
|
24
|
+
names = names[0..-2] + ["and", names[-1]] if names.length > 1
|
25
|
+
"create_#{names.join('_')}"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class <%= migration_name %> < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
<% attachments.each do |attachment| -%>
|
4
|
+
create_table :<%= class_name.underscore %>_<%= attachment.pluralize %> do |t|
|
5
|
+
t.integer :<%= class_name.underscore %>_id
|
6
|
+
t.string :style
|
7
|
+
t.binary :file_contents
|
8
|
+
end
|
9
|
+
<% end -%>
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.down
|
13
|
+
<% attachments.each do |attachment| -%>
|
14
|
+
drop_table :<%= class_name.underscore %>_<%= attachment.pluralize %>
|
15
|
+
<% end -%>
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class <%= migration_name %> < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
<% attachments.each do |attachment| -%>
|
4
|
+
create_table :<%= name.underscore.camelize.tableize %>_<%= attachment.pluralize %> do |t|
|
5
|
+
t.integer :<%= name.underscore.camelize.tableize %>_id
|
6
|
+
t.string :style
|
7
|
+
t.binary :file_contents
|
8
|
+
end
|
9
|
+
end
|
10
|
+
<% end -%>
|
11
|
+
|
12
|
+
def self.down
|
13
|
+
<% attachments.each do |attachment| -%>
|
14
|
+
drop_table :<%= name.underscore.camelize.tableize %>_<%= attachment.pluralize %>
|
15
|
+
<% end -%>
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rails/generators/active_record'
|
2
|
+
|
3
|
+
class PaperclipDatabaseGenerator < ActiveRecord::Generators::Base
|
4
|
+
desc "Create a migration to add database storage for the paperclip database storage." +
|
5
|
+
"The NAME argument is the name of your model, and the following " +
|
6
|
+
"arguments are the name of the attachments"
|
7
|
+
|
8
|
+
argument :attachment_names, :required => true, :type => :array, :desc => "The names of the attachment(s) to add.",
|
9
|
+
:banner => "attachment_one attachment_two attachment_three ..."
|
10
|
+
|
11
|
+
def self.source_root
|
12
|
+
@source_root ||= File.expand_path('../templates', __FILE__)
|
13
|
+
end
|
14
|
+
|
15
|
+
def generate_migration
|
16
|
+
migration_template "paperclip_database_migration.rb.erb", "db/migrate/#{migration_file_name}"
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def migration_name
|
22
|
+
"create_#{name.underscore}_#{attachment_names.map{|n| n.pluralize}.join('_and_')}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def migration_file_name
|
26
|
+
"#{migration_name}.rb"
|
27
|
+
end
|
28
|
+
|
29
|
+
def migration_class_name
|
30
|
+
migration_name.camelize
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class <%= migration_class_name %> < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
<% attachment_names.each do |attachment| -%>
|
4
|
+
create_table :<%= class_name.underscore %>_<%= attachment.pluralize %> do |t|
|
5
|
+
t.integer :<%= class_name.underscore %>_id
|
6
|
+
t.string :style
|
7
|
+
t.binary :file_contents
|
8
|
+
end
|
9
|
+
<% end -%>
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.down
|
13
|
+
<% attachment_names.each do |attachment| -%>
|
14
|
+
drop_table :<%= class_name.underscore %>_<%= attachment.pluralize %>
|
15
|
+
<% end -%>
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
module Paperclip
|
2
|
+
module Storage
|
3
|
+
# Store files in a database.
|
4
|
+
#
|
5
|
+
# Usage is identical to the file system storage version, except:
|
6
|
+
#
|
7
|
+
# 1. In your model specify the "database" storage option; for example:
|
8
|
+
# has_attached_file :avatar, :storage => :database
|
9
|
+
#
|
10
|
+
# The files will be stored in a new database table named with the plural attachment name
|
11
|
+
# by default, "avatars" in this example.
|
12
|
+
#
|
13
|
+
# 2. You need to create this new storage table with at least these columns:
|
14
|
+
# - file_contents
|
15
|
+
# - style
|
16
|
+
# - the primary key for the parent model (e.g. user_id)
|
17
|
+
#
|
18
|
+
# Note the "binary" migration will not work for the LONGBLOG type in MySQL for the
|
19
|
+
# file_cotents column. You may need to craft a SQL statement for your migration,
|
20
|
+
# depending on which database server you are using. Here's an example migration for MySQL:
|
21
|
+
#
|
22
|
+
# create_table :avatars do |t|
|
23
|
+
# t.string :style
|
24
|
+
# t.integer :user_id
|
25
|
+
# t.timestamps
|
26
|
+
# end
|
27
|
+
# execute 'ALTER TABLE avatars ADD COLUMN file_contents LONGBLOB'
|
28
|
+
#
|
29
|
+
# You can optionally specify any storage table name you want as follows:
|
30
|
+
# has_attached_file :avatar, :storage => :database, :database_table => 'avatar_files'
|
31
|
+
#
|
32
|
+
# 3. By default, URLs will be set to this pattern:
|
33
|
+
# /:relative_root/:class/:attachment/:id?style=:style
|
34
|
+
#
|
35
|
+
# Example:
|
36
|
+
# /app-root-url/users/avatars/23?style=original
|
37
|
+
#
|
38
|
+
# The idea here is that to retrieve a file from the database storage, you will need some
|
39
|
+
# controller's code to be executed.
|
40
|
+
#
|
41
|
+
# Once you pick a controller to use for downloading, you can add this line
|
42
|
+
# to generate the download action for the default URL/action (the plural attachment name),
|
43
|
+
# "avatars" in this example:
|
44
|
+
# downloads_files_for :user, :avatar
|
45
|
+
#
|
46
|
+
# Or you can write a download method manually if there are security, logging or other
|
47
|
+
# requirements.
|
48
|
+
#
|
49
|
+
# If you prefer a different URL for downloading files you can specify that in the model; e.g.:
|
50
|
+
# has_attached_file :avatar, :storage => :database, :url => '/users/show_avatar/:id/:style'
|
51
|
+
#
|
52
|
+
# 4. Add a route for the download to the controller which will handle downloads, if necessary.
|
53
|
+
#
|
54
|
+
# The default URL, /:relative_root/:class/:attachment/:id?style=:style, will be matched by
|
55
|
+
# the default route: :controller/:action/:id
|
56
|
+
#
|
57
|
+
module Database
|
58
|
+
|
59
|
+
def self.extended(base)
|
60
|
+
base.instance_eval do
|
61
|
+
setup_paperclip_files_model
|
62
|
+
override_default_options base
|
63
|
+
end
|
64
|
+
Paperclip.interpolates(:database_path) do |attachment, style|
|
65
|
+
attachment.database_path(style)
|
66
|
+
end
|
67
|
+
Paperclip.interpolates(:relative_root) do |attachment, style|
|
68
|
+
begin
|
69
|
+
if ActionController::AbstractRequest.respond_to?(:relative_url_root)
|
70
|
+
relative_url_root = ActionController::AbstractRequest.relative_url_root
|
71
|
+
end
|
72
|
+
rescue NameError
|
73
|
+
end
|
74
|
+
if !relative_url_root && ActionController::Base.respond_to?(:relative_url_root)
|
75
|
+
ActionController::Base.relative_url_root
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
ActiveRecord::Base.logger.info("[paperclip] Database Storage Initalized.")
|
80
|
+
end
|
81
|
+
|
82
|
+
def setup_paperclip_files_model
|
83
|
+
#TODO: This fails when your model is in a namespace.
|
84
|
+
@paperclip_files = "#{instance.class.name.underscore}_#{name.to_s}_paperclip_files"
|
85
|
+
if !Object.const_defined?(@paperclip_files.classify)
|
86
|
+
@paperclip_file = Object.const_set(@paperclip_files.classify, Class.new(::ActiveRecord::Base))
|
87
|
+
else
|
88
|
+
@paperclip_file = Object.const_get(@paperclip_files.classify)
|
89
|
+
end
|
90
|
+
@database_table = @options[:database_table] || name.to_s.pluralize
|
91
|
+
@paperclip_file.set_table_name @database_table
|
92
|
+
case Rails::VERSION::STRING
|
93
|
+
when /^2/
|
94
|
+
@paperclip_file.named_scope :file_for, lambda {|style| { :conditions => ['style = ?', style] }}
|
95
|
+
else # 3.x
|
96
|
+
@paperclip_file.scope :file_for, lambda {|style| { :conditions => ['style = ?', style] }}
|
97
|
+
end
|
98
|
+
#FIXME: This fails when using set_table_name "<myname>" in your model
|
99
|
+
#FIXME: This should be fixed in ActiveRecord...
|
100
|
+
instance.class.has_many @paperclip_files, :foreign_key => instance.class.table_name.classify.underscore + '_id'
|
101
|
+
|
102
|
+
end
|
103
|
+
private :setup_paperclip_files_model
|
104
|
+
|
105
|
+
def override_default_options(base)
|
106
|
+
if @url == base.class.default_options[:url]
|
107
|
+
@url = ":relative_root/:class/:attachment/:id?style=:style"
|
108
|
+
end
|
109
|
+
@path = ":database_path"
|
110
|
+
end
|
111
|
+
private :override_default_options
|
112
|
+
|
113
|
+
def database_table
|
114
|
+
@database_table
|
115
|
+
end
|
116
|
+
|
117
|
+
def database_path(style)
|
118
|
+
paperclip_file = file_for(style)
|
119
|
+
if paperclip_file
|
120
|
+
"#{database_table}(id=#{paperclip_file.id},style=#{style.to_s})"
|
121
|
+
else
|
122
|
+
"#{database_table}(id=new,style=#{style.to_s})"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def exists?(style = default_style)
|
127
|
+
if original_filename
|
128
|
+
!file_for(style).nil?
|
129
|
+
else
|
130
|
+
false
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Returns representation of the data of the file assigned to the given
|
135
|
+
# style, in the format most representative of the current storage.
|
136
|
+
def to_file style = default_style
|
137
|
+
if @queued_for_write[style]
|
138
|
+
@queued_for_write[style]
|
139
|
+
elsif exists?(style)
|
140
|
+
tempfile = Tempfile.new instance_read(:file_name)
|
141
|
+
tempfile.write file_contents(style)
|
142
|
+
tempfile.flush
|
143
|
+
tempfile.rewind
|
144
|
+
tempfile
|
145
|
+
else
|
146
|
+
nil
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
alias_method :to_io, :to_file
|
151
|
+
|
152
|
+
def file_for(style)
|
153
|
+
db_result = instance.send("#{@paperclip_files}").send(:file_for, style.to_s).to_ary
|
154
|
+
raise RuntimeError, "More than one result for #{style}" if db_result.size > 1
|
155
|
+
db_result.first
|
156
|
+
end
|
157
|
+
|
158
|
+
def file_contents(style)
|
159
|
+
file_for(style).file_contents
|
160
|
+
end
|
161
|
+
|
162
|
+
def flush_writes
|
163
|
+
ActiveRecord::Base.logger.info("[paperclip] Writing files for #{name}")
|
164
|
+
@queued_for_write.each do |style, file|
|
165
|
+
paperclip_file = @paperclip_file.new
|
166
|
+
paperclip_file.file_contents = file.read
|
167
|
+
paperclip_file.style = style.to_s;
|
168
|
+
instance.send(@paperclip_files) << paperclip_file
|
169
|
+
end
|
170
|
+
@queued_for_write = {}
|
171
|
+
end
|
172
|
+
|
173
|
+
def flush_deletes #:nodoc:
|
174
|
+
ActiveRecord::Base.logger.info("[paperclip] Deleting files for #{name}")
|
175
|
+
@queued_for_delete.each do |path|
|
176
|
+
/id=([0-9]+)/.match(path)
|
177
|
+
@paperclip_file.destroy $1
|
178
|
+
end
|
179
|
+
@queued_for_delete = []
|
180
|
+
end
|
181
|
+
|
182
|
+
module ControllerClassMethods
|
183
|
+
def self.included(base)
|
184
|
+
base.extend(self)
|
185
|
+
end
|
186
|
+
def downloads_files_for(model, attachment, options = {})
|
187
|
+
define_method("#{attachment.to_s.pluralize}") do
|
188
|
+
model_record = Object.const_get(model.to_s.camelize.to_sym).find(params[:id])
|
189
|
+
style = params[:style] ? params[:style] : 'original'
|
190
|
+
send_data model_record.send(attachment).file_contents(style),
|
191
|
+
:filename => model_record.send("#{attachment}_file_name".to_sym),
|
192
|
+
:type => model_record.send("#{attachment}_content_type".to_sym)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|