Paperclip
installation
brew install imagemagick
gem 'paperclip', '~> 4.1'
:Bundle
migration
:Rails generate migration AddFileUpload
:Rmigration
class AddFileUpload < ActiveRecord::Migration
def up
add_attachment :users, :avatar
end
def down
add_attachment :users, :avatar
end
end
:Rake db:migrate
:Rserver!
Model
has_attached_file :avatar,
styles: { medium: "300x300>", thumb: "100x100>" },
default_url: "/images/:style/missing.png"
validates_attachment_content_type :avatar,
content_type: /\Aimage\/.*\Z/
ちなみ画像サイズの後に >はリサイズ、 #を指定するとトリミングしてくれるらしい。
#はその大きさに拡大された
https://github.com/thoughtbot/paperclip/wiki/Thumbnail-Generation
View
<%= form_for @user, :html => { multipart: true } do |f| %>
<%= f.text_field :title %>
<%= f.file_field :avatar %>
<%= f.submit %>
<% end %>
Controller
def create
@user = User.create(user_params)
end
private
private
def user_params
params.require(:user).permit(:title, :avatar)
end
表示
<%= image_tag user.avatar.url %>
<%= image_tag user.avatar.url(:medium) %>
<%= image_tag user.avatar.url(:thumb) %>
DBに追加されたカラムは?
:Rschema users
create_table "users", force: true do |t|
t.string "title"
t.datetime "created_at"
t.datetime "updated_at"
t.string "avatar_file_name"
t.string "avatar_content_type"
t.integer "avatar_file_size"
t.datetime "avatar_updated_at"
end
ファイルの実態はどこ?
Modelに定義したsytylesディレクトリにはいってた
▾ system/
▾ users/
▾ avatars/
▾ 000/
▾ 000/
▾ 007/
▾ medium/
くにお.gif
▾ original/
くにお.gif
▾ thumb/
くにお.gif
削除
@user.avatar = nil
@user.save
もしくは
@user.destroy
ファイルの実態も勝手に消えた
S3へアップロード
インストール
gem 'aws-sdk'
:Bundle
設定ファイルを作る
もしくはモデルに書くんだけど、設定ファイルの方が楽そうなのでそうした
config/s3.yml
production:
bucket: xxxxxxxxxx
access_key_id: yyyyyyyyyy
secret_access_key: zzzzzzzzzz
development:
bucket: xxxxxxxxxx
access_key_id: yyyyyyyyyy
secret_access_key: zzzzzzzzzz
test:
bucket: xxxxxxxxxx
access_key_id: yyyyyyyyyy
secret_access_key: zzzzzzzzzz
:Rserver!
Model
has_attached_file :avatar,
styles: { medium: "300x300>", thumb: "100x100>" },
default_url: "/images/:style/missing.png",
storage: :s3,
s3_credentials: "#{Rails.root}/config/s3.yml",
path: ":attachment/:id/:style/:filename"
画像を保存するパスの変更
デフォルトは
:rails_root/public/system/:attachment/:id/:style/:filename
使える変数
:attachment(画像フィールドの複数形)
:id (レコードid)
:style(指定した画像のサイズ)
:filename (アップロードした画像名)
:extension (画像の形式)
:class(Class名)
画像ファイルの縦横を取得
:Rails generate migration AddImageDimentions
class AddImageDimension < ActiveRecord::Migration
def change
add_column :users, :image_width, :integer
add_column :users, :image_height, :integer
end
end
:Rake db:migrate
Model
before_save :extract_dimentions
def image?
avatar_content_type =~ %r{^(image|(x-)?application)/(bmp|gif|jpeg|jpg|pjpeg|png|x-png)$}
end
def extract_dimentions
return unless image?
tempfile = avatar.queued_for_write[:original]
unless tempfile.nil?
geometry = Paperclip::Geometry.from_file(tempfile)
self.image_width = geometry.width.to_i
self.image_height = geometry.height.to_i
end
end
画像のURLの難読化
/config/initializers/paperclip_defaults.rb
イニシャライザに設定しておく。:hash_sercretはSecureRandom.base64(128)をつかってる。
Paperclip::Attachment.default_options.update({
:path => ":rails_root/public/system/:attachment/:hash/:id.:extension",
:hash_secret => "適当な文字列"
})
:Rserver!
Model
has_attached_file :avatar,
url: "#{ActionController::Base.relative_url_root}/system/:attachment/:hash/:id.:extension"
ファイルのパスやURLを取得したい
save後、モデル.:attachment.pathで取得できた
@user.save
@user.avatar.path
@user.avatar.url
activeadminで使いたい
installation
Gemfile
gem 'formtastic', github: 'justinfrench/formtastic'
gem 'ransack', github: 'activerecord-hackery/ransack', branch: 'rails-4.1'
gem 'polyamorous', github: 'activerecord-hackery/polyamorous'
gem 'activeadmin', github: 'gregbell/active_admin'
:Bundle
:Rails generate active_admin:install
このへんをやる、予定
1. Ensure you have defined default url options in your environments files. Here
is an example of default_url_options appropriate for a development environment
in config/environments/development.rb:
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
In production, :host should be set to the actual host of your application.
2. Ensure you have defined root_url to *something* in your config/routes.rb.
For example:
root :to => "home#index"
3. Ensure you have flash messages in app/views/layouts/application.html.erb.
For example:
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
4. If you are deploying on Heroku with Rails 3.2 only, you may want to set:
config.assets.initialize_on_precompile = false
On config/application.rb forcing your application to not access the DB
or load models when precompiling your assets.
5. You can copy Devise views (for customization) to your app by running:
rails g devise:views
:Rake db:migrate
:Rserver!
:Rails generate active_admin:resource user
ActiveAdminでPaperclipを動かす
admin/user.rb
ActiveAdmin.register user do
form multipart: true do |f|
f.inputs 'user' do
f.input :title
#f.input :avatar, as: :file
f.input :avatar, required: false
end
f.actions
end
permit_params :title, :avatar
end
ArgumentError in Admin::users#new になったけど、
現状required: falseにすれば回避できた
http://stackoverflow.com/questions/22002259/activeadmin-and-paperclip-argumenterror
まとめ:S3(Tokyo region)を使ってpathにhashを使って、保存パスと画像サイズをDB保存
Photoモデルにresourceをattach
app/models/photo.rb
class Photo < ActiveRecord::Base
before_save :append_resource_info
has_attached_file :resource,
storage: :s3,
s3_credentials: "#{Rails.root}/config/s3.yml",
path: "/photos/:resource_user_id/:file_updated_hash.:extension",
url: ":s3_path_url",
s3_host_name: "s3-ap-northeast-1.amazonaws.com"
validates_attachment_content_type :resource,
content_type: /\Aimage\/.*\Z/
private
Paperclip.interpolates :file_updated_hash do |attachment, style|
Digest::SHA256.hexdigest(format("%s/%d", attachment.instance.resource_file_name, attachment.instance.resource_updated_at.to_i))
end
def image?
resource_content_type =~ %r{^(image|(x-)?application)/(bmp|gif|jpeg|jpg|pjpeg|png|x-png)$}
end
def append_resource_info
return unless image?
tempfile = resource.queued_for_write[:original]
unless tempfile.nil?
geometry = Paperclip::Geometry.from_file(tempfile)
self.resource_file_width = geometry.width.to_i
self.resource_file_height = geometry.height.to_i
self.resource_path = self.resource.path
end
end
end