月別アーカイブ: 2013年4月

Rails3.2 プロフィール画像をアップロードしてDBに格納。サムネイルも。

Rails 画像 アップロード
で検索するとプラグインがいろいろとでてきます。

とりあえずCarrierWaveをつかってみました。が、結局使うのをやめました。

CarrierWaveは優れたプラグインでした。
実装は非常に簡単でした。
しかし「SQLアンチパターン」という本を読み、
画像をファイルでなくDBにバイナリとして保存することを決意。

CarrierWaveでも実装できなくもなさそうでしたが、
恩恵があまり受けられないということで、
使用をやめ、独自に実装することにしました。

ただversionという感じで、いくつかのサイズを選べるという機能は気に入っていたので、
なるべく画像を使用している部分は変更のないような実装を目指しました。

Personクラスに16px, 32px, 64px, 200pxのアバター画像を保存します。

まず、マイグレーションでカラムを追加。

avatar_data16
avatar_data32
avatar_data64
avatar_data200
avatar_content_type:string

つぎに、routesを設定。
/config/routes.rb

match ‘avatar/:version’, :via => :get, :action => ‘avatar’, :as => ‘avatar’,  :on => :member

次にcontrollerを設定。(RMagickを使っています)

#作成
def set_avatar
if params[:person][:avatar_file].present?
file = params[:person][:avatar_file]
params[:person].delete(:avatar_file)
end
if file.present?
img = Magick::Image.from_blob(file.read).shift
img_16 = img.resize_to_fill(16, 16)
img_32 = img.resize_to_fill(32, 32)
img_64 = img.resize_to_fill(64, 64)
img_200 = img.resize_to_fill(200, 200)
params[:person][:avatar_data16] = img_16.to_blob
params[:person][:avatar_data32] = img_32.to_blob
params[:person][:avatar_data64] = img_64.to_blob
params[:person][:avatar_data200] = img_200.to_blob
params[:person][:avatar_content_type] = file.content_type
end
end

#取得する
def avatar
@person = Person.find(params[:id])
version = params[:version]
avatar = case version
when ‘icon’ then @person.avatar_data16
when ‘mini’ then @person.avatar_data32
when ‘thumb’ then @person.avatar_data64
when ‘normal’ then @person.avatar_data200
end
send_data(avatar, :type => @person.avatar_content_type)
end

次はviewです。
アップロード側は

<tr class=”avatar”>
<th class=”label”><%= f.label :avatar_file, ‘顔写真’%></th>
<td class=”data”><span class=”image”><%= image_tag @person.avatar_path(:mini) %></span><span class=”select_button”><%= f.file_field :avatar_file %></span></td>
</tr>

モデルにavatar_pathというメソッドを追加

include ActionDispatch::Routing::UrlFor
include Rails.application.routes.url_helpers
def avatar_path(version = :normal)
if avatar_data16.blank?
path = Person.default_avatar(version)
else
path = avatar_person_path(self, version)
end
end

def self.default_avatar(version = :normal)
case version
when :normal then ‘/assets/weiver-ui/avatar_default.png’
when :thumb then ‘/assets/weiver-ui/avatar_default.png’
when :mini then ‘/assets/weiver-ui/avatar_default_mini.png’
when :icon then ‘/assets/weiver-ui/avatar_default_icon.png’
else ”
end
end