buildって何だろう?
ActiveRecordのアソシエーションを扱うメソッドで「build」というのを初めて知りました。
class Group < ActiveRecord::Base has_many :users end class User < ActiveRecord::Base belongs_to :group end
というアソシエーションがあったときに、
@group.users.build params
みたいな感じで書くことができます。
@group.users << user
みたいなコードは save まで実行されてしまうので、場合によっては build の方がいいかと。
belongs_to についての build なら
@user.group.build params
だけじゃなくて
@user.build_group params
という書き方もできるようです。
参考:
Rails new vs build http://vinhboy.com/blog/2009/01/15/rails-new-vs-build/
ActionViewとActionControllerでurl_forの挙動が違います
URLを出力するためにつかう「url_for」というメソッドがあります。
root_path, root_url, XXXX_path, XXXX_urlなどroutes.rbで定義したURLを呼び出すメソッドでも内部的に使っています。
このurl_forやXXXX_urlですが、Controllerの中で呼ぶときとViewの中で呼ぶときで挙動が違います。
Viewで呼ぶ時はURLがエスケープされたものが返ってくるのです。
Controllerでは
http://localhost:3000/controller/action?a=1&b=2
となるところがViewだと
http://localhost:3000/controller/action?a=1&b=2
となります。
普通にブラウザを相手にする場合は問題ないですが、
ActionMailerで送信するメールの文面の場合は不具合の素になるので注意が必要です。
url_forの引数に「:escape => false」を渡すとエスケープされずに返ってきます。
file_columnで受信メールの添付画像を保存する方法
前提
Statusモデルにimageというフィールドがあって、そこがfile_columnを採用している。
メールを受信したら添付ファイルをstatus.imageに格納したい。
(1)file_columnの一部を拡張します。
vendor/plugins/file_column/lib/file_compat.rb
を以下のように変えます。
(- で始まる行が元々のコード、+ ではじまるのが変更後のコードです。)
module FileCompat # :nodoc: def original_filename - File.basename(path) + @original_filename || File.basename(path) end + + def original_filename=(name) + @original_filename = name + end
(2)StatusMailerというActionMailerを作る
メールを受信するためのクラスです。
中身はこんな感じ。
class StatusMailer < ActionMailer::Base def receive(email) Status.parse_mail(email) end end
メールを受信するための.forwardファイルは下記のような感じ。
RAILS_ROOT/script/runner -e production 'Status.receive(STDIN.read)' |
def self.parse_mail(email) # email.to を解析して 対象の status を割り出す。 status = .... # 添付画像を取得する if email.multipart? email.parts.each do |m| if m.main_type == 'image' # file_columnへの引き渡し status.save_image_from_mail m break end end end status end def save_image_from_mail(mail_part) # ランダムな文字列に拡張子を付けた形でファイル名を作る tmp_filename = Digest::SHA1.hexdigest( rand.to_s ).slice(1..10) + '.' + mail_part.sub_type # Tempfileを作って、データを格納する tmp = Tempfile::new tmp_filename tmp.puts mail_part.body # file_columnへの引き渡し準備 tmp.extend FileColumn::FileCompat tmp.original_filename = tmp_filename self.image = tmp self.save # 後片付け tmp.close end(4)動作確認 ・メーラーの適当なメールを.emlとかテキストフォーマットで保存する。 ・script/consoleを起動 ・以下を実行
$ f = open '.emlファイルのパス' $ StatusMailer.receive(f.read)
QRコードを画像で書き出す
rmagickがインストール済みを前提。
$ gem list | grep rmagick rmagick (2.12.2)
QRコードのもとになる配列を作ってくれるgemを入れる。
gem install rqrcode
QRコードの配列を画像にしてくれるモジュールを入れる。
git clone git://github.com/hal99/qrimage.git lib/qrimage mv lib/qrimage/qrimage.rb lib/qrimage.rb rm -rf lib/qrimage
そのままだとwarningが大量に発生したので(他の箇所でもrmagickを使っているから?)
qrimage.rbの中で
require 'rmagick'
を
require 'RMagick'
に書き変えた。(なぜこれでwarningが消えるかは謎。)
例えばコントローラーに下記のアクションを作っておくと、QRコードを動的に作って返す。
def qr_image image = QRImage::create_qr root_url, :size => 6 send_data image, :type => 'image/jpeg', :filename => 'qr_image.jpg' end
special thanks : RubyでQRコードを作る(画像編)
acts_as_taggable_on_steroidsの使い方
インストールする(githubに引っ越してるから注意)
ruby script/plugin install git://github.com/jviney/acts_as_taggable_on_steroids.git ruby script/generate acts_as_taggable_migration rake db:migrate
Manualモデルというのをtaggableにするとして
Manualモデルには
acts_as_taggable
と書く。
routes.rbには
map.resources :manuals do |manual| manual.resources :tags, :collection => { :remove => :delete } end
と書く。
(/manuals/:manual_id/tags のURLで受け入れアクションが生成される。)
コントローラーはこんな感じ。
class TagsController < ApplicationController layout nil before_filter :load_manual def index @tags = @manual.tag_list end def create keys = params[:name].gsub(/ /," ").scan(/\S+/) @tags = @manual.tag_list.add(keys) @manual.save render :action => 'index' end def remove @tags = @manual.tag_list.remove(params[:name]) @manual.save render :action => 'index' end private def load_manual @manual = Manual.find(params[:manual_id]) end end
views/tags/index.html.erbはこんな感じ。
<div id="tag"> <% form_remote_tag :update => "tag", :url => manual_tags_url(@manual) do %> <h3>キーワード</h3> <div><%= text_field_tag 'name' %><%= submit_tag 'キーワードをつける' %></div> <% end %> <ul> <% @tags.each do |tag|%> <li><%=h tag %> <%= link_to_remote( '[削除]',:update => "tag", :url => remove_manual_tags_url(@manual,:name => tag), :method => :delete ) %> </li> <% end %> </ul> </div>
以上です。
PostgreSQL + Ludia + PostGIS な環境作り
MacPortsだと Ludia の環境が PostgreSQL 8.1 しか見つからず、PostGISは 8.2 or 8.3 しかありませんでした。
PostGISよりLudiaの方が手動でインストールするのが面倒だったので、Ludia を port install して PostGISの方は手動でインストールすることにしました。
PostgreSQL 8.1 + Ludia
インストール
sudo port install postgresql81-ludia
DBの領域作り
sudo mkdir -p /opt/local/var/db/postgresql81/defaultdb sudo chown postgres:postgres /opt/local/var/db/postgresql81/defaultdb sudo su postgres -c '/opt/local/lib/postgresql81/bin/initdb -D /opt/local/var/db/postgresql81/defaultdb'
サーバ起動
sudo su postgres -c '/opt/local/lib/postgresql81/bin/pg_ctl -D /opt/local/var/db/postgresql81/defaultdb start'
データベースにLudia用の関数とか作成
psql81 -f /opt/local/share/postgresql81/pgsenna2.sql -U postgres project_development
インストール
wget http://postgis.refractions.net/download/postgis-1.3.6.tar.gz tar zxvf postgis-1.3.6.tar.gz cd postgis-1.3.6 ./configure --with-pgsql=/opt/local/lib/postgresql81/bin/pg_config make sudo make install
PostGIS用の関数などをデータベースに定義
createlang plpgsql -U postgres project_development psql81 -f /opt/local/share/lwpostgis.sql -U postgres project_development