Rails2.0の足回りと中級者への道

第3回 Rails2.0で作るRESTfulアプリケーション(後編)

この記事を読むのに必要な時間:およそ 6 分

最終的なアプリケーションコード

ここまでの機能を含む最終的なコードの簡単な解説をしていきます。

モデル

まずは,モデルから解説します。

app/models/link.rb

class Link < ActiveRecord::Base
  has_many :assorts
  has_many :tags, :through=>:assorts
  belongs_to :user

  def tag_names=(value)
    Tag.transaction do
      self.save
      tag_ids = self.tags.map(&:id)
      self.tags.delete(Tag.find(tag_ids)) if self.tags
      tags = value.split(" ")
      tags.each do |t|
        self.tags << Tag.find_or_create_by_name(t)
      end
    end
  end

  def tag_names
    self.tags.map(&:name).join(" ")
  end

  def self.create_with_user(condition, current_user)
    @link = Link.create(condition) 
    @link.user = current_user    
    @link
  end

  def self.find_by_user_name_and_tag_id(user_name, tag_id)
    Link.find_by_sql([<<-SQL, {:user_name => user_name, :tag_id => tag_id}])
      SELECT 
        links.*
      FROM
        users,
        tags,
        assorts,
        links
      WHERE
        users.login = :user_name
      AND
        links.user_id = users.id
      AND
        assorts.link_id = links.id
      AND
        tags.id = :tag_id
      AND
        tags.id = assorts.tag_id
    SQL
  end
end

リンクを管理する,Linkモデルです。

代入メソッドtag_names=で,既存のタグを削除し,新規のタグを作成する付け直しの作業をしています。先にsaveメソッドを呼んでいるのは,has_many: throughで多対多の関連を作成した場合の制限によるものです。

また自身以外のユーザによる変更は発生しないはずですが,念のため Transaction ブロックで囲みトランザクション処理をしています。

取得メソッドtag_namesでは,リンクに関連付けられたタグのリストから,スペースで区切られたタグ名一覧を作成しています。この2点の修正で,Linkモデルにtag_names属性を追加します。

find_by_user_name_and_tag_idでは,ユーザ名とタグIDからリンク一覧を検索しています。この箇所だけではなく,miniciousでは積極的にfind_by_sqlを利用しています。

app/models/tags.rb

class Tag < ActiveRecord::Base
  has_many :assorts
  has_many :links, :through=>:assorts

  def self.find_by_user_name(user_name)
    Tag.find_by_sql([<<-SQL, {:user_name => user_name}])
      SELECT 
        count(tags.name) cnt
        ,tags.*
      FROM
        users,
        tags,
        assorts,
        links
      WHERE
        users.login = :user_name
      AND
        links.user_id = users.id
      AND
        assorts.link_id = links.id
      AND
        tags.id = assorts.tag_id
      GROUP BY tags.name
    SQL
  end
end

タグを管理するTagモデルのfind_by_user_nameメソッドでは,ユーザが持つタグの一覧を検索しています。SQLのCOUNT関数で,ユーザが持つ全リンク内のタグの件数を取得し,⁠cnt」というタグ件数を保持する属性を作成しています。ActiveRecordでは,Rubyのメタプログラミングにより「メソッドが生えてくる」ようなイメージで属性が利用できます。

コントローラ

つづいて,コントローラです。

app/controllers/links_controller.rbから抜粋

class LinksController < ApplicationController

  before_filter :login_required , :only => [:new, :create, :edit, :update, :destroy]

  # 以下省略
end

リンクURIをコントロールするLinksControllerです。before_filterの:onlyオプションで認証を行うアクションの指定を行っています。更新系のアクションにのみ認証を設定しています。

上のコード例以外の修正として,URIの変更にともない,リダイレクトするパスの修正を行っています。

著者プロフィール

鎌田達哉(かまだたつや)

SI企業勤務。10年ほど前にはじめて自分で行ったプログラミングはRubyによるものであったが,語ってもにわかには信じてもらえないような紆余曲折を経て現在に至る。現在は,JVM上の言語実装に興味あり。ありがちですが,Scalaにはまり中。