Ruby on Rails 2.1.x Tutorialをやってみる。
インストールと動作確認
環境はDebian GNU/Linux Lenny。まずは、gemのアップデート。私の環境だとgemはaptでいれたのでgem1.8としてインストールされている。
% sudo gem1.8 update --system
次にRails2.1のインストール。
% sudo gem1.8 install rails
実際に動くかどうかをチェック。
% mkdir Rails2.1 % cd Rails21. % rails demo % cd demo % ruby script/server
ブラウザでhttp://localhost:3000にアクセスしてみる。ちゃんと表示されて入れば動いている。
モデルの構築とMigration
チュートリアルではデータベースとしてMySQLを使い、かつ、例題用に新たなlibraryというプロジェクトを作っているがさっきつかったdemoをそのまま利用することにする。なお、Rails2.1のデータベースはデフォルトでSQLite3になっているので、別のデータベースを使いたい場合にはプロジェクト作成時に以下のようにデータベースを指定する必要があるらしい。
rails -d mysql demo
~/demo/config/database.ymlを以下の用にする(ほとんどデフォルトから変えていない)
# SQLite version 3.x # gem install sqlite3-ruby (not necessary on OS X Leopard) development: adapter: sqlite3 database: db/library.development.sqlite3 timeout: 5000 # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: adapter: sqlite3 database: db/library.test.sqlite3 timeout: 5000 production: adapter: sqlite3 database: db/library.production.sqlite3 timeout: 5000
次にモデルを構築。~/Rails2.1/demoに移動して、以下のコマンドを実行。
% ruby script/generate model Book exists app/models/ exists test/unit/ exists test/fixtures/ create app/models/book.rb create test/unit/book_test.rb create test/fixtures/books.yml create db/migrate create db/migrate/20080806031037_create_books.rb % ruby script/generate model Subject exists app/models/ exists test/unit/ exists test/fixtures/ create app/models/subject.rb create test/unit/subject_test.rb create test/fixtures/subjects.yml exists db/migrate create db/migrate/20080806031046_create_subjects.rb
チュートリアル曰く「モデル作成の場合には単数形でかつ先頭の文字を大文字にすること。」
Railsにおけるモデル間(テーブル間)の関係は3種類あるとのこと。集合論でお馴染みの関係。
- one-to-one(1対1関係)
- one-to-many(1対多関係)
- many-to-many(多対多関係)
この関係をhas_one, has_many, belongs_to,has_and_belongs_to_manyを使って明示する必要があるとのこと。app/model/book.rbとapp/model/subject.rbをそれぞれ以下のように編集する。
class Book < ActiveRecord::Base belongs_to :subject end
class Subject < ActiveRecord::Base has_many :books end
SubjectとBookの関係は1対多関係で、一つのSubjectが複数のBookを持つので「has_many :books」と複数形になるとのこと。Railsはここいら辺が難しいね。
次にデータベースにデータを格納する際の値チェックを用意する validates〜というもの。これはそれぞれのモデルの部分に書く。book.rbを以下の用に編集する。
class Book < ActiveRecord::Base belongs_to :subject validates_presence_of :title validates_numericality_of :price, :message=>"Error Message" end
次にMigrationをする。データベースへの変更作業をスクリプト化しておきデータベースをそのスクリプトにしたがって管理する仕組みらしい。~/Rails2.1/demoに移動して以下のコマンドを実行する。
% ruby script/generate migration books exists db/migrate create db/migrate/20080806032900_books.rb % ruby script/generate migration subjects exists db/migrate create db/migrate/20080806032916_subjects.rb
次にdb/migrate/20080806032900_books.rbを編集する。なお、20080806032900の部分は自動生成されるので上記コマンドを実行した環境によって違う。ここに日付が入るのはRails2.1の新機能らしい。
class Books < ActiveRecord::Migration def self.up create_table :books do |t| t.string :title, :limit => 32, :null => false t.float :price t.integer :subject_id t.text :description t.timestamp :created_at end end def self.down drop_table :books end end
self.upでかかれている内容がMigrationをするときに実行される。Role back(前のデータベースの状態に戻す)場合にはself.downでかかれている内容が実行される。Railsのテーブルには必ずidというコラムが含まれているが、これは自動的に番号が割り振られる(auto increment)なので書く必要はないらしい。
次にdb/migrate/20080806032916_subjects.rbも以下のように編集する。
class Subjects < ActiveRecord::Migration def self.up create_table :subjects do |t| t.string :name end Subject.create :name => "Physics" Subject.create :name => "Mathematics" Subject.create :name => "Chemistry" Subject.create :name => "Pshchology" Subject.create :name => "Geography" end def self.down drop_table :subjects end end
「Subject.create :name => "Physics"」という部分でレコードを追加している。テストデータはこうやって組み込むみたい。便利。
それで、Migration実行。
% rake db:migrate (in /home/gotoh/Ruby/Rails2.1/demo) == 20080806031037 CreateBooks: migrating ====================================== -- create_table(:books) -> 0.0070s == 20080806031037 CreateBooks: migrated (0.0073s) ============================= == 20080806031046 CreateSubjects: migrating =================================== -- create_table(:subjects) -> 0.0230s == 20080806031046 CreateSubjects: migrated (0.0232s) ========================== == 20080806032900 Books: migrating ============================================ -- create_table(:books) rake aborted! SQLite3::SQLException: table "books" already exists: CREATE TABLE "books" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar(32) NOT NULL, "price" float DEFAULT NULL NULL, "subject_id" integer DEFAULT NULL NULL, "description" text DEFAULT NULL NULL, "created_at" datetime DEFAULT NULL NULL) (See full trace by running task with --trace)
はい、ひっかかりました。理由は、20080806031037_create_books.rbがModel作ったときに存在しているから。20080806031037_create_books.rbの中身はこれ。
class CreateBooks < ActiveRecord::Migration def self.up create_table :books do |t| t.timestamps end end def self.down drop_table :books end end
〜_create_books.rbと〜_create_subjects.rbに集約する。その後、一度初期状態までrolebackして再度Migration
% rake db:migrate VERSION=0 (in /home/gotoh/Ruby/Rails2.1/demo) == 20080806031046 CreateSubjects: reverting =================================== -- drop_table(:subjects) -> 0.0074s == 20080806031046 CreateSubjects: reverted (0.0076s) ========================== == 20080806031037 CreateBooks: reverting ====================================== -- drop_table(:books) -> 0.0060s == 20080806031037 CreateBooks: reverted (0.0062s) ============================= % rake db:migrate (in /home/gotoh/Ruby/Rails2.1/demo) == 20080806031037 CreateBooks: migrating ====================================== -- create_table(:books) -> 0.1617s == 20080806031037 CreateBooks: migrated (0.1620s) ============================= == 20080806031046 CreateSubjects: migrating =================================== -- create_table(:subjects) -> 0.0074s == 20080806031046 CreateSubjects: migrated (0.1147s) ==========================
特に指定しなければconfig/database.ymlのdevelopment用のデータベースに処理が行われる。データベースを指定してMigrationする場合には、環境変数RAILS_ENVにproduction, test, developmentをそれぞれ指定する。Cシェル系ならばsetコマンドを使う。
% set RAILS_ENV=production
bash系ならば、exportコマンドを使う
% export RAILS_ENV=production
SQLiteの場合データベースはdb以下に作られる。今回の場合はこんな感じのデータベースになった。
% sqlite3 db/library.development.sqlite3 SQLite version 3.5.9 Enter ".help" for instructions sqlite> .table books schema_migrations subjects sqlite> .schema books CREATE TABLE "books" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar(32) NOT NULL, "price" float DEFAULT NULL NULL, "subject_id" integer DEFAULT NULL NULL, "description" text DEFAULT NULL NULL, "created_at" datetime DEFAULT NULL NULL); sqlite> .schema subjects CREATE TABLE "subjects" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255) DEFAULT NULL NULL); sqlite> .exit
- Migrationの参考ページ
コントローラーの作成
次にContorollerの作成に移る。
% ruby script/generate controller Book exists app/controllers/ exists app/helpers/ create app/views/book exists test/functional/ create app/controllers/book_controller.rb create test/functional/book_controller_test.rb create app/helpers/book_helper.rb
app/controllers/book_controller.rbを以下のように編集する。ここの説明はチュートリアルを参照。
class BookController < ApplicationController def list @books = Book.find(:all) end def show @book = Book.find(params[:id]) end def new @book = Book.new @subjects = Subject.find(:all) end def create @book = Book.new(params[:book]) if @book.save redirect_to :action => 'list' else @subjects = Subject.find(:all) render :action => 'new' end end def edit @book = Book.find(params[:id]) @subjects = Subject.find(:all) end def update @book = Book.find(params[:id]) if @book.update_attributes(params[:book]) redirect_to :action => 'show', :id => @book else @subjects = Subject.find(:all) render :action => 'edit' end end def delete Book.find(params[:id]).destroy redirect_to :action => 'list' end def show_subjects @subject = Subject.find(params[:id]) end end
よく分からないのは、インスタンス変数とローカル変数の使い分け。確か、View部分でインスタンス変数を参照できるのだけど、ここの仕組みがいまいち理解できない。あとはハッシュへのアクセスの仕方。文字列を使うときと:idのようにコロンを使ったときの区別がわからない。だんだん、Rails 0.9ぐらいでプログラム書いていたときの疑問点を思い出してきた。
ビューの作成
次に各メソッドごとにViewを用意する。Viewファイルは「メソッド名.html.erb」とするらしい。まず、listメソッドのViewをapp/view/book/list.html.erbとして用意する。中身は以下のとおり。
<% if @books.blank? %> <p>There are not any books currently in the system.</p> <% else %> <p>These are the current books in our system</p> <ul id="books"> <% @books.each do |c| %> <li><%= link_to c.title, {:action => 'show', :id => c.id} -%></li> <% end %> </ul> <% end %> <p><%= link_to "Add new Book", {:action => 'new' }%></p>
ここまでで、http://localhost:3000/book/listにアクセスすると、newメソッドへのリンクが張られたページが閲覧でき、newメソッド部分(http://localhost:3000/book/new)で本を登録するとlistメソッド部分に登録した本が表示される。さすがRails。こういうのを見れるようにするのは早い。
次にshowメソッドのViewをapp/view/book/show.html.erbとして用意する。中身は以下のとおり。
<h1><%= @book.title %></h1> <p><strong>Price: </strong> $<%= @book.price %><br /> <strong>Subject :</strong> <%= @book.subject.name %><br /> <strong>Created Date:</strong> <%= @book.created_at %><br /> </p> <p><%= @book.description %></p> <hr /> <%= link_to 'Back', {:action => 'list'} %>
@book.subject.nameというので、subjectsテーブルのデータを一緒に引っ張ってこれるのはとても便利。perlのDBIx::Classでもできるらしいのだけど、ハッシュでアクセスするよりもオブジェクトのメソッド呼び出し(アクセッサーっていうんだっけ?)で呼び出すのは綺麗なような気がする。ここはRailsというかActionRecordの好きなところ。
次はapp/view/book/edit.html.erb。中身は以下のとおり。
<h1>Edit Book Detail</h1> <% form_tag :action => 'update', :id => @book do %> <p><label for="book_title">Title</label>: <%= text_field 'book', 'title' %></p> <p><label for="book_price">Price</label>: <%= text_field 'book', 'price' %></p> <p><label for="book_subject">Subject</label>: <%= collection_select(:book, :subject_id, @subjects, :id, :name) %></p> <p><label for="book_description">Description</label><br/> <%= text_area 'book', 'description' %></p> <%= submit_tag "Save changes" %> <% end %> <%= link_to 'Back', {:action => 'list' } %>
new.html.erbとの違いは、form_tagの飛ばし先がupdateメソッドであることと、デフォルトの値として:id => @bookが指定されていること。ここいらへんのインスタンス変数とHTMLヘルパーの連携がちょっとわかりづらい。
これにともないapp/view/book/list.html.erbを修正。
<% if @books.blank? %> <p>There are not any books currently in the system.</p> <% else %> <p>These are the current books in our system</p> <ul id="books"> <% @books.each do |c| %> <li><%= link_to c.title, {:action => 'show', :id => c.id} -%> <b> <%= link_to 'Edit', {:action => "edit", :id => c.id} %></b></li> <% end %> </ul> <% end %> <p><%= link_to "Add new Book", {:action => 'new' }%></p>
deleteメソッドを呼び出すために、app/view/book/list.html.erbを修正。
<% if @books.blank? %> <p>There are not any books currently in the system.</p> <% else %> <p>These are the current books in our system</p> <ul id="books"> <% @books.each do |c| %> <li><%= link_to c.title, {:action => 'show', :id => c.id} -%> <b> <%= link_to 'Edit', {:action => "edit", :id => c.id} %></b> <b> <%= link_to "Delete", {:action => 'delete', :id => c.id}, :confirm => "Are you sure you want to delete this item?" %></li> <% end %> </ul> <% end %> <p><%= link_to "Add new Book", {:action => 'new' }%></p>
show_subjectsメソッドのViewをapp/view/book/show_subjects.html.erbとして用意。
<h1><%= @subject.name -%></h1> <ul> <% @subject.books.each do |c| %> <li><%= link_to c.title, :action => "show", :id => c.id -%></li> <% end %> </ul>
そして、app/view/book/show.html.erbを修正。
<h1><%= @book.title %></h1> <p><strong>Price: </strong> $<%= @book.price %><br /> <strong>Subject :</strong> <%= link_to @book.subject.name, :action => "show_subjects", :id => @book.subject.id %><br /> <strong>Created Date:</strong> <%= @book.created_at %><br /> </p> <p><%= @book.description %></p> <hr /> <%= link_to 'Back', {:action => 'list'} %>
list.html.erbも修正。
<ul id="subjects"> <% Subject.find(:all).each do |c| %> <li><%= link_to c.name, :action => "show_subjects", :id => c.id %></li> <% end %> </ul> <% if @books.blank? %> <p>There are not any books currently in the system.</p> <% else %> <p>These are the current books in our system</p> <ul id="books"> <% @books.each do |c| %> <li><%= link_to c.title, {:action => 'show', :id => c.id} -%> <b> <%= link_to 'Edit', {:action => "edit", :id => c.id} %></b> <b> <%= link_to "Delete", {:action => 'delete', :id => c.id}, :confirm => "Are you sure you want to delete this item?" %></li> <% end %> </ul> <% end %> <p><%= link_to "Add new Book", {:action => 'new' }%></p>
レイアウトとCSS
各メソッドで共通のHTMLのヘッダ部分やフッタ部分はapp/view/layoutに置くことができる。app/view/layout/standard.html.erbを作成し、中身を以下とする。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html;. charset=iso-8859-1" /> <meta http-equiv="Content-Language" content="en-us" /> <title>Library Info System</title> <%= stylesheet_link_tag "style" %> </head> <body id="library"> <div id="container"> <div id="header"> <h1>Library Info System</h1> <h3>Library powered by Ruby on Rails</h3> </div> <div id="content"> <%= yield -%> </div> <div id="sidebar"></div> </div> </body> </html>
yieldの部分にメソッドごとのViewが入る。app/controller/book_controller.rbで使用するレイアウトファイルを定義する。
class BookController < ApplicationController layout 'standard' def list @books = Book.find(:all) end 〜以下略〜
スタイルシートは~/Rails2.1/demo/public/stylesheets以下に置く。style.cssを以下の中身でこのディレクトリに置く。
body { font-family: Helvetica, Geneva, Arial, sans-serif; font-size: small; font-color: #000; background-color: #fff; } a:link, a:active, a:visited { color: #CD0000; } input { margin-bottom: 5px; } p { line-height: 150%; } div#container { width: 760px; margin: 0 auto; } div#header { text-align: center; padding-bottom: 15px; } div#content { float: left; width: 450px; padding: 10px; } div#content h3 { margin-top: 15px; } ul#books { list-style-type: none; } ul#books li { line-height: 140%; } div#sidebar { width: 200px; margin-left: 480px; } ul#subjects { width: 700px; text-align: center; padding: 5px; background-color: #ececec; border: 1px solid #ccc; margin-bottom: 20px; } ul#subjects li { display: inline; padding-left: 5px; }
Ajax
scaffoldの項は飛ばし、Ajaxを使ってみる。
目的は、先ほど作った本のリストアプリケーションのSubjectをAjaxを用いて編集すること。まず、Subject用のコントローラーを用意する。
% ruby script/generate controller Subject exists app/controllers/ exists app/helpers/ create app/views/subject exists test/functional/ create app/controllers/subject_controller.rb create test/functional/subject_controller_test.rb create app/helpers/subject_helper.rb
app/controllers/subject_controller.rbを以下のように編集。
class SubjectController < ApplicationController layout 'standard' def list @subjects = Subject.find(:all) end def show @subject = Subject.find(params[:id]) end def create @subject = Subject.new(params[:subject]) if @subject.save render :partial => 'subject', :object=> @subject end end end
次にビューを作成する。app/view/subject/list.html.erbを以下のように用意する。
<h1>Listing Subjects</h1> <ul id="subject_list"> <% @subjects.each do |c| %> <li><%= link_to c.name, :action => 'show', :id => c.id %> <%= "(#{c.books.count})" -%></li> <% end %> </ul>
app/model/subject.rbで、「has_many :books」と定義しているので、booksテーブルの情報をc.books.countで持ってこれるらしい、なるほど。
次にshow.html.erbを用意
<h1><%= @subject.name -%></h1> <ul> <% @subject.books.each do |c| %> <%= link_to c.title, :controller => "book", :action => "show",:id => c.id -%> <% end %> </ul>
次に、Ajaxを使ってcreateメソッドを実行するためにjavascriptライブラリを読み込む。Rails付属のjavascriptライブラリを読み込むためには、app/views/layaout/standard.html.erbを修正する。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html;. charset=iso-8859-1" /> <meta http-equiv="Content-Language" content="en-us" /> <title>Library Info System</title> <%= stylesheet_link_tag "style" %> <%= javascript_include_tag :defaults %> </head> 〜以下略〜
この「<%= javascript_include_tag :defaults %>」が読み込み命令。そして、app/views/subject/list.html.erbを編集する。
<h1>Listing Subjects</h1> <ul id="subject_list"> <% @subjects.each do |c| %> <li><%= link_to c.name, :action => 'show', :id => c.id %> <%= "(#{c.books.count})" -%></li> <% end %> </ul> <p id="add_link"><%= link_to_function("Add a Subject", "Element.remove('add_link'); Element.show('add_subject')")%></p> <div id="add_subject" style="display:none;"> <% form_remote_tag(:url => {:action => 'create'}, :update => "subject_list", :position => :bottom, :html => {:id => 'subject_form'}) do %> Name: <%= text_field "subject", "name" %> <%= submit_tag 'Add' %> <% end %> </div>
付け加えた最初の部分で、リンクを表示する。
<p id="add_link"><%= link_to_function("Add a Subject", "Element.remove('add_link'); Element.show('add_subject')")%></p>
このリンクがクリックされると以下の部分が表示される。
<div id="add_subject" style="display:none;"> <% form_remote_tag(:url => {:action => 'create'}, :update => "subject_list", :position => :bottom, :html => {:id => 'subject_form'}) do %> Name: <%= text_field "subject", "name" %> <%= submit_tag 'Add' %> <% end %> </div>
ここに入力された内容は、createメソッドへ飛ばされる。createメソッドはpartialメソッドでページ全体ではなくページの一部に出力を返す。その出力部分をapp/views/subject/_subject.html.erbとして以下のように置く。partialメソッドで呼び出されるViewファイルはアンダーバーで始まらなければならない規則があるとのこと。
<li id="subject_<%= subject.id %>"> <%= link_to subject.name, :action => 'show', :id => subject.id %> <%= "(#{subject.books.count})" -%> </li>
ファイルのアップロード
新たにプロジェクトを用意する。
% cd ~/Rails2.1 % rails upload
db/database.ymlはデフォルトで使用する。次にアップロードファイルを置くディレクトリを作成する。
% cd upload % mkdir -p public/data
DataFileモデルを用意する。ただし、このモデルはデータベース上にはなく、アップロードするデータファイルを扱うモデルとのこと。
% ruby script/generate model DataFile exists app/models/ exists test/unit/ exists test/fixtures/ create app/models/data_file.rb create test/unit/data_file_test.rb create test/fixtures/data_files.yml create db/migrate create db/migrate/20080806063836_create_data_files.rb
app/models/data_file.rbを編集。
class DataFile < ActiveRecord::Base def self.save(upload) name = upload['datafile'].original_filename directory = "public/data" # create the file path path = File.join(directory,name) # write the file File.open(path,"wb") {|f| f.write(upload['datafile'].read) } end end
ここいらへんはRubyの基礎知識が足りないとわかりづらい。「File.open(path,"wb") {|f| f.write(upload['datafile'].read) }」のfが何だかよくわからない。ファイルハンドラ?そして、upload['datafile'].readでアップロードしたファイルを読み込んでその読み込んだ結果をfに書き込んでいるということかな。チュートリアルの方を読んでもあんまりわからない。
今度はコントローラーを作る。
% ruby script/generate controller Upload exists app/controllers/ exists app/helpers/ create app/views/upload exists test/functional/ create app/controllers/upload_controller.rb create test/functional/upload_controller_test.rb create app/helpers/upload_helper.rb
app/controllers/upload_controller.rbを編集。
class UploadController < ApplicationController def index render :file => 'app/views/upload/uploadfile.html.erb' end def uploadFile post = DataFile.save(params[:upload]) render :text => "File has been uploaded successfully" end end
renderメソッドの引数でファイルを呼ぶか、テキストメッセージを表示するか指定できるのか。
次にビューを用意する。app/views/upload/uploadfile.html.erbの中身を以下とする。
<h1>File Upload</h1> <% form_tag ({:action => 'uploadFile'}, :multipart => true) do %> <p><label for="upload_file">Select File</label> : <%= file_field 'upload', 'datafile' %></p> <%= submit_tag "Upload" %> <% end %>
WEBrickを立ち上げて、ファイルをアップロードしたらエラーがでた。
undefined method `save' for DataFile(Table doesn't exist):Class
言われてみればデータベースを用意していない。Migrationする。
% rake db:migrate
そして、もう一度チャンレンジする。それでもだめ。
undefined method `save' for DataFile(id: integer, created_at: datetime, updated_at: datetime):Class
app/models/data_file.rbを以下のように(ApplicationControllerを継承)したらうまくいった。
class DataFile < ApplicationController def self.save(upload) name = upload['datafile'].original_filename directory = "public/data" # create the file path path = File.join(directory,name) # write the file File.open(path,"wb") {|f| f.write(upload['datafile'].read) } end end
メールを送る
新たなプロジェクトemailsを作成する
% rails emails
次にconfig/environment.rbの末尾に以下を付け加える。
ActionMailer::Base.delivery_method = :sendmail
SMTPサーバを使う場合は:smtp、Unix環境などで/usr/lib/sendmailなどが使える場合は:sendmailを使う。今回はsendmailを使う。
次にメーラーを作成する。
% ruby script/generate mailer Emailer exists app/models/ create app/views/emailer exists test/unit/ create test/fixtures/emailer create app/models/emailer.rb create test/unit/emailer_test.rb
app/models/emailer.rbを編集。
class Emailer < ActionMailer::Base def contact(recipient, subject, message, sent_at = Time.now) @subject = subject @recipients = recipient @from = 'no-reply@yourdomain.com' @sent_on = sent_at @body['title'] = 'This is title' @body["email"] = 'sender@yourdomain.com' @body["message"] = message @headers = { } end end
次にコントローラーを作成。
% ruby script/generate controller Emailer exists app/controllers/ exists app/helpers/ exists app/views/emailer exists test/functional/ create app/controllers/emailer_controller.rb create test/functional/emailer_controller_test.rb create app/helpers/emailer_helper.rb
app/controllers/emailer_controller.rbを編集。
class EmailerController < ApplicationController def sendmail recipient = params[:email] subject = params[:subject] message = params[:message] Emailer.deliver_contact(recipient, subject, message) return if request.xhr? render :text => 'Message sent successfully' end def index render :file => 'app/views/emailer/index.html.erb' end end
ビューを作る。app/views/emailer/index.html.erbを以下の内容で作成。
<h1>Send Email</h1> <% form_tag :action => 'sendmail' do %> <p><label for="email_subject">Subject</label>: <%= text_field 'email', 'subject' %></p> <p><label for="email_recipient">Recipient</label>: <%= text_field 'email', 'recipient' %></p> <p><label for="email_message">Message</label><br/> <%= text_area 'email', 'message' %></p> <%= submit_tag "Send" %> <% end %>
app/views/emailer/contact.html.erbを以下の内容で作成する。
Hi! You are having one email message from <%= @email %> with a title <%= @title %> and following is the message: <%= @message %> Thanks
WEBrickで試してみる。私の環境ではメールはうまく送れなかった。log/development.logにメールの内容があった。
終わりに
Railsはチュートリアルの後が難しい。チュートリアルを終えてのメモ。
今回チュートリアルをやってよかったこと。
- Migrationがとても便利そう。個々のデータベース管理システムから独立してくれているのはありがたい
- データベースの中身をオブジェクトとしてもってくるのはやっぱり便利
- SQLiteとWEBricのおかげで開発環境を整えるのが楽、その分公開環境を整えるのは面倒でしんどいけど。
疑問点
- timezoneがUTCになっているのでJSTに直す方法を探す必要あり
- エラーメッセージの日本語化の方法を探すを探す必要あり
- GetTextと組み合わせて使う方法を練習する必要あり
- ログイン認証とセッション管理の方法を調べる必要あり
- 日本語メールを送れるようにする方法を調べる必要あり
- 画像などを表示する時にはどこにおいて、どうやってアクセスすれば良いのかを調べる
- 既存のデータベースのデータをMigrationと合わせるにはどうすればよいの?
そもそもとして、
- ハッシュへのアクセスの仕方params[:id]の:idが何なのか調べる