Ruby on Rails 3 でAjaxを扱うための基礎

やりたいこと

Rails3でAjaxを扱うための基礎として、メソッドをAjaxで呼び出し、取得データをViewに反映するところまで。

方法

「:remote => true」によりlink,formをAjax化し、Ajax用のerbファイルを作成する。
$ vi app/views/chapters/show.html.erb

<%= link_to 'ツイート取得処理(Ajax化)', { :controller => 'chapters', :action => 'tweets' }, :remote => true %>
  • Ajaxにより呼び出されるメソッドを修正
$ vi app/controllers/chapters_controller.rb

  # Ajax処理によるツイート取得のためのメソッド
  def tweets
    @tweets = Tweet.find_all_by_chapter_id(params[:id])
    # ※ここでrenderで返却してしまうと、Ajax用のerbファイルが呼ばれなくなるので注意。
  end
  • Ajax用のerbファイル作成
    • メソッド名.「html」.erbではなく、メソッド名.「js」.erbであるところがミソ。
$ vi app/views/chapters/tweets.js.erb

$('#tweets').html(
  "<%= escape_javascript(@tweets.to_json) %>"
);
  • Ajaxで取得したデータを表示する領域をViewに作成
$ vi app/views/chapters/show.html.erb

<div id='tweets'>
</div>

参考サイト

  • 特に無し

Ruby on Railsで独自のルーティングとメソッドを追加したい

やりたいこと

Ruby on Railsでresourcesを使用しない独自のルーティングと、それに対応するメソッドを追加したい。

方法

route.rbにおいてmemberブロックを使用してルーティング追加
  • この例では各チャプター毎にツイートの一覧を返却する「tweets」ルーティングを追加
$ vi config/route.rb
TestApplication::Application.routes.draw do
  resources :animes do
    resources :chapters do
      member do
        get 'tweets'
      end
    end
  end
end
ルーティング確認
$ rake routes
tweets_anime_chapter GET    /animes/:anime_id/chapters/:id/tweets(.:format) chapters#tweets
      anime_chapters GET    /animes/:anime_id/chapters(.:format)            chapters#index
                     POST   /animes/:anime_id/chapters(.:format)            chapters#create
   new_anime_chapter GET    /animes/:anime_id/chapters/new(.:format)        chapters#new
  edit_anime_chapter GET    /animes/:anime_id/chapters/:id/edit(.:format)   chapters#edit
       anime_chapter GET    /animes/:anime_id/chapters/:id(.:format)        chapters#show
                     PUT    /animes/:anime_id/chapters/:id(.:format)        chapters#update
                     DELETE /animes/:anime_id/chapters/:id(.:format)        chapters#destroy
              animes GET    /animes(.:format)                               animes#index
                     POST   /animes(.:format)                               animes#create
           new_anime GET    /animes/new(.:format)                           animes#new
          edit_anime GET    /animes/:id/edit(.:format)                      animes#edit
               anime GET    /animes/:id(.:format)                           animes#show
                     PUT    /animes/:id(.:format)                           animes#update
                     DELETE /animes/:id(.:format)                           animes#destroy
追加したルーティングに対応するメソッドを追加
  • 上記で確認した通り、「tweet」ルーティングに対応するメソッドは「chapters#tweets」であるため、
    Chapterコントローラーにtweetsメソッドを追加する。
$ vi app/controllers/chapters_controller.rb
  # GET /animes/1/chapters/1/tweets
  # GET /animes/1/chapters/1/tweets.json
  def tweets
    @chapter = Chapter.find(params[:id])
    @tweets = @chapter.tweets

    respond_to do |format|
      format.html
      format.json { render json: @tweets }
    end
  end

参考サイト

  • 特に無し

Ruby on Railsで親子関係にあるモデルのルーティング設定

やりたいこと

Ruby on Railsで親子関係にあるモデルのルーティングを設定したい。

方法

route.rbにおいてモデルを下記の様にネストさせる。
$ vi config/route.rb
TestApplication::Application.routes.draw do
  resources :animes do
    resources :chapters
  end
end
ルーティング確認
$ rake routes
    anime_chapters GET    /animes/:anime_id/chapters(.:format)          chapters#index
                   POST   /animes/:anime_id/chapters(.:format)          chapters#create
 new_anime_chapter GET    /animes/:anime_id/chapters/new(.:format)      chapters#new
edit_anime_chapter GET    /animes/:anime_id/chapters/:id/edit(.:format) chapters#edit
     anime_chapter GET    /animes/:anime_id/chapters/:id(.:format)      chapters#show
                   PUT    /animes/:anime_id/chapters/:id(.:format)      chapters#update
                   DELETE /animes/:anime_id/chapters/:id(.:format)      chapters#destroy
            animes GET    /animes(.:format)                             animes#index
                   POST   /animes(.:format)                             animes#create
         new_anime GET    /animes/new(.:format)                         animes#new
        edit_anime GET    /animes/:id/edit(.:format)                    animes#edit
             anime GET    /animes/:id(.:format)                         animes#show
                   PUT    /animes/:id(.:format)                         animes#update
                   DELETE /animes/:id(.:format)                         animes#destroy
View修正
  • アニメ詳細画面にて各話の一覧を表示し、ツイート件数を各話詳細画面へのリンクに設定
$ vi app/views/animes/show.html.erb
下記を追記。
<% @anime.chapters.each do |chapter| %>
    <tr>
    <td><%= chapter.chapter %></td>
    <td><%= chapter.title %></td>
    <td><%= chapter.start_time %></td>
    <td><%= chapter.end_time %></td>
    <td>
      <%= link_to chapter.tweets.count, anime_chapter_path(@anime, chapter) %></td>
  </tr>
<% end %>
動作確認
  • ヘルパーメソッドにより生成されたリンク先を確認
    正常に各話詳細画面に遷移することを確認。
<%= link_to chapter.tweets.count, anime_chapter_path(@anime, chapter) %><a href="/animes/3/chapters/3">0</a>

参考サイト

Ruby on Railsで子テーブルのデータをソートする方法

やりたいこと

Viewで@chapter.tweets的な感じで子テーブルのデータを一覧で表示する際にデータをソートしたい。

方法

親モデルのhas_manyにorder byを指定
$ vi app/models/chapter.rb
class Chapter < ActiveRecord::Base
  has_many :tweets, :order => 'tweet_id DESC'
  belongs_to :anime
  attr_accessible :chapter, :end_time, :start_time, :title, :tweet_collect_end_flg, :tweet_collect_start_flg, :anime_id
end

参考サイト

ActiveRecordをRails以外から使用する方法

やりたいこと

ActiveRecordRails以外の普通のスクリプトとかから使いたい。

方法

スクリプトファイル内でRailsの設定系のファイルを読み込む。
#coding: utf-8
require 'active_record'
require '/railsdir/config/boot'
require '/railsdir/config/environment'

config = YAML.load_file("/railsdir/config/database.yml")

ActiveRecord::Base.establish_connection(config["development"])

p Anime.all
上記スクリプトを実行時にエラー発生
  • エラー内容
WARN: Unresolved specs during Gem::Specification.reset:
      multi_json (~> 1.0)
WARN: Clearing out unresolved specs.
Please report a bug if this causes problems.
  • gemの依存関係で怒られてるみたいなので、各パッケージの最新バージョン以外を削除。
$ sudo gem cleanup

参考サイト

Ruby on Railsでアプリ全体にベーシック認証をかける方法

やりたいこと

Railsでアプリ全体にベーシック認証をかけたい。

方法

アプリ共通のコントローラーにベーシック認証の設定を追加
$ app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery
  # 以下を追加
  before_filter :auth
  private
  def auth
    authenticate_or_request_with_http_basic do |user,pass|
      user == 'user' && pass == 'pass'
    end
  end
end

Ruby on RailsでDBにユニーク制約を付与する方法

やりたいこと

  • RailsでDBにユニーク制約を付与したい。

方法

マイグレーションファイルを新規作成してユニークインデックスを追加
$ rails generate migration AddIndexAnimeIdAndChapterToChapters
      invoke  active_record
      create    db/migrate/20130429145932_add_index_anime_id_and_chapter_to_chapters.rb
  • ユニークインデックス追加を設定
$ vi db/migrate/20130429145932_add_index_anime_id_and_chapter_to_chapters.rb
class AddIndexAnimeIdAndChapterToChapters < ActiveRecord::Migration
  def change
    add_index :chapters, [:anime_id, :chapter], :unique => true
  end
end
$ rake db:migrate
==  AddIndexAnimeIdAndChapterToChapters: migrating ============================
-- add_index(:chapters, [:anime_id, :chapter], {:unique=>true})
   -> 0.0204s
==  AddIndexAnimeIdAndChapterToChapters: migrated (0.0207s) ===================

参考サイト