じゃあ、いつRails始めるの?... 今でしょ!
実践 Rails ―強力なWebアプリケーションをすばやく構築するテクニック
- 作者: Brad Ediger,株式会社クイープ
- 出版社/メーカー: オライリージャパン
- 発売日: 2008/10/27
- メディア: 大型本
- 購入: 7人 クリック: 90回
- この商品を含むブログ (43件) を見る
はじめに
Ruby on Rails入門 (全46回) - プログラミングならドットインストール
PythonistaからRubyistへの鞍替えを試みている@yutakikucです。DotInstall等を通してRuby on Railsの基礎を学び中なので学習した内容をまとめていきます。Yahoo!勤務時代はWebFWを自作していた経験もありFWについてはある程度知識を持っている僕から見てもRailsはとても便利ものだということが直ぐに分かりますが、色々と自動的にやり過ぎてくれて理解が難しくもあったりします。このエントリー内容は超初歩的なものになるので、これから勉強したいという人向けに記述します。この記事の基礎となっているのはdotainstallです。dotainstallのlessonは全部で46回ありますが、#4,#5,#09〜#036を見ると良いと思います。
RailsのInstall
RailsInstallに必要なPackageInstall
RailsのInstallに必要なPackageを先にInstallしておきます。以下のPackageが無いとRailsのInstall時にErrorが大量に出力される可能性があります。
$ sudo yum install gcc zlib zlib-devel yaml openssl openssl-devel curl curl-devel sqlite sqlite-devel readline readline-devel mysql mysql-devel -yNodeのInstall
後々に必要になるServerSideのJavascriptの実行環境としてNodeをInstallしておきます。yumからinstall出来なかったのでSourceを直接DownloadしてCompileします。※注意:rails newでプロジェクトを作成した後にGemfileを修正してtherubyracerをinstallすればNodeは必要無くなります。
$ wget -N http://nodejs.org/dist/node-latest.tar.gz $ tar xzf node-latest.tar.gz $ cd node-v0.10.5 $ ./configure $ make && sudo make installRubyのInstall
Ruby 2.0.0-p0 リリース
最新のRuby versionは2.0.0です。これをダウンロードしてinstallします。ruby -vとgem -vでinstallを確認します。$ wget "ftp://ftp.ruby-lang.org/pub/ruby/2.0/ruby-2.0.0-p0.tar.gz" $ tar xzf ruby-2.0.0-p0.tar.gz $ ./configure $ make && sudo make install $ ruby -v ruby 2.0.0p0 (2013-02-24 revision 39474) [x86_64-linux] $ gem -v 2.0.0RailsのInstall
gemでinstallするだけです。gemでのLibraryInstall先は標準の場合/usr/local/lib/ruby/gems/になるので覚えておくと良いと思います。
$ sudo gem install rails $ rails -v Rails 3.2.13Railsの新しいProject作成とWebrickの起動
Railsの新しいProjectを作成し、Railsに同包されているWebrickを起動します。起動後にRailsProjectが動作することを確認します。これで一旦RailsInstallの説明は完了です。
$ rails new sample create create README.rdoc create Rakefile create config.ru create .gitignore create Gemfile create app create app/assets/images/rails.png ....... run bundle install ....... Your bundle is complete! $ cd sample $ rails s => Booting WEBrick => Rails 3.2.13 application starting in development on http://0.0.0.0:3000 => Call with -d to detach => Ctrl-C to shutdown server [2013-05-03 01:38:57] INFO WEBrick 1.3.1 [2013-05-03 01:38:57] INFO ruby 2.0.0 (2013-02-24) [x86_64-linux] [2013-05-03 01:38:57] INFO WEBrick::HTTPServer#start: pid=3729 port=3000 $ w3m "http://localhost:3000" • Browse the documentation □ Rails Guides □ Rails API □ Ruby core □ Ruby standard library Welcome aboard You’re riding Ruby on Rails!
Railsの基礎
Rails Command
rails newで新しいプロジェクトを作成します。ここではプロジェクト名をsampleとします。--skip-bundleというオプションを付けることで既にinstallされているgemを新たに追加せずにプロジェクトを作成することができます。※注意:RailsのdefaultでのDBはsqlite3なので、mysqlにしたい場合は-dオプションを付ける必要があります。
$ rails new sample $ rails new sample -d mysqlrails generateでModel/Controllerを作成します。generateはgと省略することができます。ここでは名簿管理をするModelを作成します。Listという名前のmodelで名前と年齢を管理します。name:string age:integerはデータ型の定義です。
$ rails g model List name:string age:integer invoke active_record create db/migrate/20130503163317_create_lists.rb create app/models/list.rb invoke test_unit create test/unit/list_test.rb create test/fixtures/lists.ymlControllerの生成もModelと同じようにgenerate出来ます。命名規則ですがControllerは複数形、Modelは単数形にします。ControllerのgenerateでViewも作成されます。
$ rails g controller Lists create app/controllers/list_controller.rb invoke erb create app/views/list invoke test_unit create test/controllers/list_controller_test.rb invoke helper create app/helpers/list_helper.rb invoke test_unit create test/helpers/list_helper_test.rb invoke assets invoke coffee create app/assets/javascripts/list.js.coffee invoke scss create app/assets/stylesheets/list.css.scssgenerateで作成されたModelをmigrationします。DBへの反映はrakeコマンドを使います。
$ rake db:migrate == CreateLists: migrating ==================================================== -- create_table(:lists) -> 0.0045s == CreateLists: migrated (0.0046s) ===========================================URLのroutingを設定するにはconfig/routes.rbファイルを修正し、rakeコマンドで反映します。まずはroutes.rbにを以下のようにresources :listsを追加してrake routesコマンドで反映します。rake routesコマンドで生成された内容を見ても分かるようにURLのFormatとHTTPMethodで呼び出したい処理の切り替えができるようになっていて、綺麗な形式になっています。
Sample::Application.routes.draw do resources :lists$ rake routes lists GET /lists(.:format) lists#index POST /lists(.:format) lists#create new_list GET /lists/new(.:format) lists#new edit_list GET /lists/:id/edit(.:format) lists#edit list GET /lists/:id(.:format) lists#show PUT /lists/:id(.:format) lists#update DELETE /lists/:id(.:format) lists#destroyrails consoleでrailsのdebugを行います。下ではListに対してnameとageのデータを格納するための処理をdebugしています。処理を行ったsqlも表示されています。
$ rails console irb(main):002:0> l = List.new(:name => 'Kikuchi', :age => 30 ) => #<List id: nil, name: "Kikuchi", age: 30, created_at: nil, updated_at: nil> irb(main):003:0> l.save (0.7ms) begin transaction SQL (68.3ms) INSERT INTO "lists" ("age", "created_at", "name", "updated_at") VALUES (?, ?, ?, ?) [["age", 30], ["created_at", Fri, 03 May 2013 18:00:33 UTC +00:00], ["name", "Kikuchi"], ["updated_at", Fri, 03 May 2013 18:00:33 UTC +00:00]] (59.5ms) commit transaction => truerails dbconsole(rails db)でdbへの格納が正常に行われているかどうかを確認します。
$ rails db sqlite> .tables lists schema_migrations sqlite> select * from lists; 1|Kikuchi|30|2013-05-03 18:00:33.753423|2013-05-03 18:00:33.753423 sqlite> .exitrails destroyで作成したファイルを削除することが出来ます。destroyはdと省略することができます。
$ rails d model List $ rails d controller Lists $ rails d migration listsrails serverで作成したプロジェクトをWebRickで確認できるようにします。serverはsと省略することができます。※rails sは作成したプロジェクトの直下で実行する必要あります。
$ rails sRailsの日本語化と文字コードの設定
まずはbundle listでi18nが入っていることを確認します。入っていればconfig/localesディレクトリに移動して、rails-i18n/rails/locale/ja.yml at master · svenfuchs/rails-i18n · GitHub のja.ymlファイルをdownloadします。
$ bundle list | grep i18n * i18n (0.6.4) $ cd config/locales $ wget "https://raw.github.com/svenfuchs/rails-i18n/master/rails/locale/ja.yml" $ head ja.yml ja: date: abbr_day_names: - 日 - 月 - 火 - 水 - 木 - 金 - 土downloadしたymlファイルを有効化するためにconfig/application.rbを修正します。日本語化を行うためにconfig.i18n.default_locale = :jaに設定します。また文字コードをutf-8にしたいのでconfig.encoding = 'utf-8'を追記します。
require File.expand_path('../boot', __FILE__) require 'rails/all' # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. Bundler.require(:default, Rails.env) module Sample class Application < Rails::Application # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. # config.time_zone = 'Central Time (US & Canada)' # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] config.encoding = 'utf-8' config.i18n.default_locale = :ja end endRailsのDirectory構成
bundle installしたDirectoryの中身は以下のようになります。
GemfileがProject全体のLibraryの管理などをするファイルです。ここを更新して必要なLibraryをinstallすることができます。
app/models,views,controllersにmvcファイルをそれぞれ設置します。app/assetsにimg,css,javascriptを設置します。
config/application.rbにapplication全体の設定、config/database.ymlにdbの設定、urlの設定はroutes.rbに記述します。
accesslogはlog/development.logに記録されます。$ tree . ├── Gemfile ├── Gemfile.lock ├── README.rdoc ├── Rakefile ├── app │   ├── assets │   │   ├── images │   │   │   └── rails.png │   │   ├── javascripts │   │   │   └── application.js │   │   └── stylesheets │   │   └── application.css │   ├── controllers │   │   └── application_controller.rb │   ├── helpers │   │   └── application_helper.rb │   ├── mailers │   ├── models │   └── views │   └── layouts │   └── application.html.erb ├── config │   ├── application.rb │   ├── boot.rb │   ├── database.yml │   ├── environment.rb │   ├── environments │   │   ├── development.rb │   │   ├── production.rb │   │   └── test.rb │   ├── initializers │   │   ├── backtrace_silencers.rb │   │   ├── inflections.rb │   │   ├── mime_types.rb │   │   ├── secret_token.rb │   │   ├── session_store.rb │   │   └── wrap_parameters.rb │   ├── locales │   │   └── en.yml │   └── routes.rb ├── config.ru ├── db │   ├── development.sqlite3 │   └── seeds.rb ├── doc │   └── README_FOR_APP ├── lib │   ├── assets │   └── tasks ├── log │   └── development.log ├── public │   ├── 404.html │   ├── 422.html │   ├── 500.html │   ├── favicon.ico │   ├── index.html │   └── robots.txt ├── script │   └── rails ├── test │   ├── fixtures │   ├── functional │   ├── integration │   ├── performance │   │   └── browsing_test.rb │   ├── test_helper.rb │   └── unit ├── tmp │   ├── cache │   │   └── assets │   ├── pids │   │   └── server.pid │   ├── sessions │   └── sockets └── vendor ├── assets │   ├── javascripts │   └── stylesheets └── plugins 40 directories, 40 filesContollerの作成
rake routesで表示されたメソッドをapp/controllers/lists_controller.rbに定義します。定義するメソッドはindex/create/new/edit/show/update/destroyですが、ここでは簡単な説明のため一覧表示のindexだけを説明します。newとcreateが少し定義がややこしいんですが、newは新規登録画面を呼び出し、createはnewからデータを受け取ってDBに格納する感じだそうです。rubyのメソッド定義はdef〜endでできるので、def indexを作成します。@listsのようにインスタンス変数に格納したデータはview側で参照が出来ます。データをViewで呼び出すようにapp/views/lists/index.html.erbを定義します。定義したviewを閲覧するためにw3mコマンドでhttp://localhost:3000/listsにアクセスすると想定していたデータが取得出来ました。またlogs/development.logにaccessやerrorのlogが記録されます。
class ListsController < ApplicationController def index #modelは単数形なのでList それを全て取得する @lists = List.all end end<% @lists.each do |list| %> <li>Name : <%= list.name %> Age : <%= list.age %></li> <% end %>$ w3m "http://localhost:3000/lists" Name : Kikuchi Age : 30 $ tail logs/development.log Started GET "/lists" for 127.0.0.1 at 2013-05-04 03:28:45 +0900 Processing by ListsController#index as HTML ^[[1m^[[35mList Load (0.2ms)^[[0m SELECT "lists".* FROM "lists" Rendered lists/index.html.erb within layouts/application (5.3ms) Completed 200 OK in 16ms (Views: 14.1ms | ActiveRecord: 0.2ms)Viewの中では<% %>、<%= %>などのrubyを埋め込むためのERB記号やhelperとしての便利メソッドが用意されています。標準でのhelperはgemでactionpackというLibraryをinstallした時点で/usr/local/lib/ruby/gems/2.0.0/gems/actionpack-4.0.0.rc1/lib/action_view/helpers/に様々なhelperが追加されます。link_toというメソッドはurl_helper.rbというファイルに定義されています。また自分でhelperを追加したい場合はapp/helpers/application_helper.rb にdef〜endで定義します。
list_pathというようなものはhelperは自動的に定義されるようです。_pathとすることでactionに関するURLを生成してくれます。更に _ _pathなどのControllerで定義したメソッドのURLも呼び出す事ができます。その他のViewに関する使い方は以下のページが参考になると思います。ビュー(view) - Railsドキュメント <% %> #rubyの命令が使える。 <%= 文字列 %> #実体参照系でescapeを行った上で表示する。 <%= 文字列.html_safe %> #escapeせずに出力する場合 <%== 文字列 %> #escapeせずに出力する場合 <%= link_to 'home', '/' %> #linkを生成 <%= link_to 'list', list_path(list) %> #listへのリンクを生成 <%= link_to 'new', new_list_path() %> #newへのリンクを生成 <%= image_tag("image.png",:size=>"50x50",:alt=>"画像") %> #画像を埋め込み 引数でsizeとaltを指定できる。def link_to(name = nil, options = nil, html_options = nil, &block) html_options, options = options, name if block_given? options ||= {} html_options = convert_options_to_data_attributes(options, html_options) url = url_for(options) html_options['href'] ||= url content_tag(:a, name || url, html_options, &block) endModelにValidationを設定
値のCheckを行いたい場合はValidatesを使うことができます。ValidatesはModelに仕込みます。Validatesに関しては以下のページに詳しく説明が載っています。Ruby on Rails Guides: Active Record Validations and Callbacks
class List < ActiveRecord::Base validates :name, :presence => true #nameは必須とする validates :age, :presence => true, :length => {:maxinum => 3 } #ageは必須で、最大の長さは3とする endsqlite3からMysqlへのmigration
RailsのDefaultDBはsqlite3です。rails newの説明でも書きましたがMysqlを使用したい場合はオプションでdatabaseをMysqlに変更する必要があります。もし途中からMysqlに変更したくなった場合の方法をここでは記載します。まずはsqlite3のdataをymlファイルとしてdumpします。そのためにはGemfileにgem 'yaml_db'を追記してbundle installします。dumpする実行コマンドはrake db:dumpです。次にconfig/database.ymlをsqlite3からmysql2に変更します。最後にdumpしたファイルをrake db:loadしてデータのmigraionは完了になります。
$ vi Gemfile # gem 'yaml_db', gem 'mysql2'を追記 $ rake db:dump $ vi config/database.yml #sqlite3→mysql2に変更 development: adapter: mysql2 pool: 5 timeout: 5000 username: "root" password: "" database: "lists" socket: /var/lib/mysql/mysql.sock $ rake db:load -- create_table("lists", {:force=>true}) -> 0.1321s -- initialize_schema_migrations_table() -> 0.0572s -- assume_migrated_upto_version(20130504004202, ["/home/yuta/work/rails/sample/db/migrate"]) -> 0.0283s
Rubyの基礎文法
Rubyの基礎文法についてもまとめを書いておきます。文法が少しPythonに似ているところもあってPythonistaとしてはRubyはとても学習しやすい言語だと感じました。
CommentOut
単数行は#、複数行は=begin,=endで囲みます。
#!/usr/bin/env ruby # -*- encoding: utf-8 -*- =begin print "Hello World!" #改行無しで出力 =endオブジェクト指向
rubyでは全てをオブジェクトで扱うと考えます。オブジェクトとはデータとメソッドを持つ型です。メソッドはデータ.メソッド()のように記述します。
#!/usr/bin/env ruby # -*- encoding: utf-8 -*- puts "Hello World!".length() # Hello World!という文字列オブジェクトに対してlengthメソッドがある。出力は12 puts length( "Hello World!" ) # error出力の違い
以下ではprint,puts,pの違いを書きます。
#!/usr/bin/env ruby # -*- encoding: utf-8 -*- print "Hello World!" #改行無しで出力 puts "Hello World!" #改行ありで出力 p "Hello World!" #データの型を明示して出力破壊的メソッド
破壊的メソッドは変数を上書きしてしまう仕組みです。以下の例を見たほうが分かりやすいと思います。
#!/usr/bin/env ruby # -*- encoding: utf-8 -*- #破壊的メソッド s = "Hello World!" puts s.chop #sは上書きされず、Hello Worldが出力される。 puts s #sは上書きされていないので、Hello World!が出力される。 puts s.chop! #sは上書きされていて、Hello Worldが出力される。 puts s #sは上書きされていて、Hello Worldが出力される。文字列追記
書き方が幾つかあります。少し調べてみたところ+=は処理コストが大きいようなので、それ以外を選択するのが良いと思います。
#!/usr/bin/env ruby # -*- encoding: utf-8 -*- #文字列の追記 s = "Hello World!" s << " New World!" # << による追記 s += " Next World!" # += による追記 s.concat( " Last World!" ) # concat による追記 puts s文字列検索
index,includeメソッドで文字列に特定の文字が含まれるか検索できます。indexは検索文字の位置を特定、includeはtrue/falseを取得出来ます。
#!/usr/bin/env ruby # -*- encoding: utf-8 -*- #文字列の検索 s = "Hello World!" puts s.index( "llo" ) #文字列が現れる位置を出力 結果は2 puts s.include?( "foo" ) #文字列が含まれるかどうかをtrue/falseで返す。結果はfalse文字列の置換
最初の文字列だけを置換する場合はsub、文字列全てを置換する場合はgsubを利用します。
#!/usr/bin/env ruby # -*- encoding: utf-8 -*- #文字列の置換 s = "foo foo bar" puts s.sub( "foo", "bar" ) #最初の文字列を置換 puts s.gsub( "foo", "bar" ) #文字列全てを置換配列
配列の定義は[]の中にカンマで区切ります。
#!/usr/bin/env ruby # -*- encoding: utf-8 -*- #配列の定義 values = [1,2,3,4,5] puts values #配列の中身全てを出力 puts values[2..3] #配列の添字が2〜3を出力 puts values[2...3] #配列の添字が2〜3で、最後の中身を含めずに出力 puts values[0] #最初の要素を出力 puts values[-1] #最後の要素を出力配列操作
配列の要素を操作するunshift/push/shift/pop/uniq/sort/joinを説明します。unshiftで先頭に要素を追加、pushで末尾に要素を追加、shiftで先頭から要素を取り出す、popで末尾から要素を取り出す、uniqで重複削除、sortで昇順にsort.reverseで降順に並び替え、joinで要素を結合する事ができます。またinclude?で要素が含まれるかをtrue/falseで確認することができます。
#!/usr/bin/env ruby # -*- encoding: utf-8 -*- #配列の操作 values = [1,2,3,4,5] puts values.shift #先頭から要素を取り出す puts values.pop #末尾から要素を取り出す values.unshift(0) #先頭に要素を追加する values.push(6) #末尾に要素を追加する values.push(0) puts values.uniq #配列の要素をuniq puts values.push(1).sort #配列の要素をsort puts values.sort.reverse #配列の要素を降順にsort #配列の要素をチェック if values.include?(6) puts "6 is exist" end #配列の要素を結合 puts values.join( " and " )連想配列の定義
連想配列の定義は{}とkey/value間は=>で定義します。each文で定義したkey/valueを抽出でき、has_key,has_valueでkey/valueの存在を確認する事ができます。
#!/usr/bin/env ruby # -*- encoding: utf-8 -*- # 連想配列 scores = { "KIKUCHI"=>100, "TANAKA"=>70, "KATO"=>30 } scores.each do |key,value| puts "#{key}'s score is #{value}" end key = "KIKUCHI" if scores.has_key?(key) puts "#{key}' key is exist" else puts "#{key}' key is not exist" end value = 50 if scores.has_value?(50) puts "#{value} is exist" else puts "#{value} is not exist" end制御文法
ここではif/for/while/times/eachについて書きます。制御文はif/for/while〜endで定義します。繰り返しの方法にはその他timesやeachがあり、eachは連想配列のkey/valueを参照するときに使えると思います。
#!/usr/bin/env ruby # -*- encoding: utf-8 -*- # 制御文法 ## 制御文法はif/for/while等〜endとして定義する str = "Hello World!" # if if str.include?("!") puts "str includes !" end ## 以下全部10回繰り返す # for for i in 1..10 do puts "Hello World! #{i}" end # each data = 1..10 data.each do |i| puts "Hello World! #{i}" end # while i = 1 while i <= 10 do puts "Hello World! #{i}" i+=1 end # times 10.times do |i| puts "Hello World! #{i+1}" end ## 連想配列の繰り返し scores = { "KIKUCHI" => 100, "TANAKA" => 70, "KATO" => 30 } scores.each do |key,value| puts "#{key}'s score is #{value}" endメソッドの定義
新たにメソッドを追加したい場合はdef〜endで定義します。当然returnで値を返すこともできます。
#!/usr/bin/env ruby # -*- encoding: utf-8 -*- #出力メソッドを新たに定義 def echo( word = "foo" ) puts word,word end #10で割り切れるかを確認するメソッド def div10( value ) if value % 10 == 0 return true else return false end end echo( "Hello World!" ) puts div10( 3 ) puts div10( 10 )Classの定義
Classの定義はClass〜endで行います。また継承も使うことができて 継承したいClass < 継承元Classのように行います。
#!/usr/bin/env ruby # -*- encoding: utf-8 -*- # AnimalClassを定義 class Animal def initialize(name) @name = name end def echo(word) puts word end end # AnimalClassを継承するDogClassを定義 class Dog < Animal def run puts @name + " is running!" end end pochi = Dog.new( "pochi" ) pochi.run pochi.echo("wanwan")