久しぶりの rails

友人からログインして請求書みたいなのが見れるナニ、のサンプルさくっと作れねぇ? というリクエストがあったのでこっそり着手。
railsplayground の rails は 1.2.3 との事

# rails -v
Rails 1.2.3
#

とりあえずプロジェクト作っとく。

# rails proto
(略
#

で、丁度 1.2.3 で login_engine なログ (Rails 1.2.3でEngines及びLogin Engineプラグインを利用するCommentsAdd Starzabikaname) を発見したのでこれをカンペにして作業着手。とりあえず入れるプラグインは

  • engines
  • login_engine
  • plugin_migration

を入れとけば良いのかな。

# script/plugin discover

全部 Y にしたんだけどええんかな。

# script/plugin install engines
(中略
The engines plugin is now installed. Feels good, right? Yeah. 
You knew it would.

Once the warm, fuzzy glow has subsided, be sure to read the contents 
of the README and UPGRADING files if you're migrating this application 
from Rails 1.1.x to 1.2.x.

Have a great day!

なコト言われたんですが、とりあえずスルーで次。

# script/plugin install login_engine
# script/plugin install plugin_migration

む。しまった。こうだったみたい。

# script/generate plugin_migration login_engine
Access denied for user 'root'@'localhost' (using password: NO)
#

む。これはデータベース作っとかんと駄目なんか。当分 rails サワッてないんで微妙感満点やっさ。
で、railsplayground の FAQ を確認。SQLite3 が使える模様。自分のログも見つつ作業しなければならないあたりが微妙なんですが構わず続ける。

# cat config/database.yml
# MySQL (default setup).  Versions 4.1 and 5.0 are recommended.
#
# Install the MySQL driver:
#   gem install mysql
# On MacOS X:
#   gem install mysql -- --include=/usr/local/lib
# On Windows:
#   gem install mysql
#       Choose the win32 build.
#       Install MySQL and put its /bin directory on your path.
#
# And be sure to use new-style password hashing:
#   http://dev.mysql.com/doc/refman/5.0/en/old-client.html
development:
  adapter: sqlite3 
  database: db/sqlite3.dev
  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/sqlite3.test
  timeout: 5000

production:
  adapter: sqlite3
  database: db/sqlite3.production
  timeout: 5000
#

で、

# script/generate plugin_migration login_engine
      create  db/migrate
      create  db/migrate/001_login_engine_to_version_1.rb
#

を、でけた。あと請求データみたいのも作っとくか。と言いつつ中身見てびっくり。

# cat db/migrate//001_login_engine_to_version_1.rb
class LoginEngineToVersion1 < ActiveRecord::Migration
  def self.up
    Rails.plugins["login_engine"].migrate(1)
  end

  def self.down
    Rails.plugins["login_engine"].migrate(0)
  end
end
#

ひえー。テーブルの列な情報がこれではさっぱりワケワカらんし。やっぱ先にテーブル作っておいた方が良さげ。設定追記が必要だな。ええとまず config/environment.rb に

Rails::Initializer.run do |config|
  # Settings in config/environments/* take precedence over those specified here

  # Skip frameworks you're not going to use (only works if using vendor/rails)
  # config.frameworks -= [ :action_web_service, :action_mailer ]

  # Only load the plugins named here, by default all plugins in vendor/plugins are loaded
  # config.plugins = %W( exception_notification ssl_requirement )

  # Add additional load paths for your own custom dirs
  # config.load_paths += %W( #{RAILS_ROOT}/extras )

  # Force all environments to use the same logger level 
  # (by default production uses :info, the others :debug)
  # config.log_level = :debug

  # Use the database for sessions instead of the file system
  # (create the session table with 'rake db:sessions:create')
  # config.action_controller.session_store = :active_record_store

  # Use SQL instead of Active Record's schema dumper when creating the test database.
  # This is necessary if your schema can't be completely dumped by the schema dumper, 
  # like if you have constraints or database-specific column types
  # config.active_record.schema_format = :sql

  # Activate observers that should always be running
  # config.active_record.observers = :cacher, :garbage_collector

  # Make Active Record use UTC-base instead of local time
  # config.active_record.default_timezone = :utc

  # See Rails::Configuration for more options
  config.plugins = [ "engines", "*" ] # add
end

を追加して

require File.join(File.dirname(__FILE__), 'boot')

の下に

require File.join(RAILS_ROOT, "vendor", "plugins", "engines", "lib", "engines", "deprecated_config_support")

を追加ですか。で、いっちゃん下に

module LoginEngine
  config :salt, "hoge"
  config :use_email_notification, false
end

ッスか。で後は app/controller/application.rb に

# Filters added to this controller apply to all controllers in the application.
# Likewise, all the methods added will be available for all controllers.

require 'login_engine'  # add

class ApplicationController < ActionController::Base
  before_filter :login_required  # add

  include LoginEngine            # add
  helper :user                   # add
  model :user                    # add
  # Pick a unique cookie name to distinguish our session data from others'
  session :session_key => '_proto_session_id'
end

な情報追加と app/helpers/application_helper.rb を

# Methods added to this helper will be available to all templates in the application.
module ApplicationHelper
  include LoginEngine   # add
end

ってしておけば migration の準備は完了なはず。

# rake migrate
== LoginEngineToVersion1: migrating ===========================================
== InitialSchema: migrating ===================================================
-- create_table(nil, {:force=>true})
rake aborted!
SQLite3::SQLException: near "(": syntax error: 
   CREATE TABLE  ("id" INTEGER PRIMARY KEY NOT NULL, 
                  "login" varchar(80) DEFAULT '' NOT NULL, 
                  "salted_password" varchar(40) DEFAULT '' NOT NULL, 
                  "email" varchar(60) DEFAULT '' NOT NULL, 
                  "firstname" varchar(40) DEFAULT NULL, 
                  "lastname" varchar(40) DEFAULT NULL, 
                  "salt" varchar(40) DEFAULT '' NOT NULL, 
                  "verified" integer DEFAULT 0, 
                  "role" varchar(40) DEFAULT NULL, 
                  "security_token" varchar(40) DEFAULT NULL, 
                  "token_expiry" datetime DEFAULT NULL, 
                  "created_at" datetime DEFAULT NULL, 
                  "updated_at" datetime DEFAULT NULL, 
                  "logged_in_at" datetime DEFAULT NULL, 
                  "deleted" integer DEFAULT 0, 
                  "delete_after" datetime DEFAULT NULL) 

(See full trace by running task with --trace)
#

って駄目ぢゃん。って参考資料に見落しあり。確かにテーブル名が無いな。config/environment.rb にテーブル名な記述が必要らしい。

module LoginEngine
  config :salt, "hoge"
  config :use_email_notification, false
  config :user_table, "users"
end

やれやれ。

# rake migrate
== LoginEngineToVersion1: migrating ===========================================
== InitialSchema: migrating ===================================================
-- create_table("users", {:force=>true})
   -> 0.0225s
== InitialSchema: migrated (0.0230s) ==========================================

== LoginEngineToVersion1: migrated (0.0323s) ==================================

The rake task migrate has been deprecated, please use the replacement version db:migrate

できた模様。さっそく確認。

# sqlite3 db/sqlite3.dev 
SQLite version 3.3.7
Enter ".help" for instructions
sqlite> .tables
plugin_schema_info  schema_info         users             
sqlite> .scheme users
unknown command or invalid arguments:  "scheme". Enter ".help" for help
sqlite> .help
.databases             List names and files of attached databases
.dump ?TABLE? ...      Dump the database in an SQL text format
.echo ON|OFF           Turn command echo on or off
.exit                  Exit this program
.explain ON|OFF        Turn output mode suitable for EXPLAIN on or off.
.header(s) ON|OFF      Turn display of headers on or off
.help                  Show this message
.import FILE TABLE     Import data from FILE into TABLE
.indices TABLE         Show names of all indices on TABLE
.load FILE ?ENTRY?     Load an extension library
.mode MODE ?TABLE?     Set output mode where MODE is one of:
                         csv      Comma-separated values
                         column   Left-aligned columns.  (See .width)
                         html     HTML <table> code
                         insert   SQL insert statements for TABLE
                         line     One value per line
                         list     Values delimited by .separator string
                         tabs     Tab-separated values
                         tcl      TCL list elements
.nullvalue STRING      Print STRING in place of NULL values
.output FILENAME       Send output to FILENAME
.output stdout         Send output to the screen
.prompt MAIN CONTINUE  Replace the standard prompts
.quit                  Exit this program
.read FILENAME         Execute SQL in FILENAME
.schema ?TABLE?        Show the CREATE statements
.separator STRING      Change separator used by output mode and .import
.show                  Show the current values for various settings
.tables ?PATTERN?      List names of tables matching a LIKE pattern
.timeout MS            Try opening locked tables for MS milliseconds
.width NUM NUM ...     Set column widths for "column" mode
sqlite> .schema users
(略
sqlite> .quit
#

できております。で、別の migration 作るのってどうやんだっけ、と言いつつ自分のログを見ると model 作成でできるのを発見。そりゃそうか、と言いつつ scheme を検討。なんて名前にするかな。payment と invoice ??

# ./script/generate model Payment
      exists  app/models/
      exists  test/unit/
      exists  test/fixtures/
      create  app/models/payment.rb
      create  test/unit/payment_test.rb
      create  test/fixtures/payments.yml
      exists  db/migrate
      create  db/migrate/002_create_payments.rb
# ./script/generate model Invoice
      exists  app/models/
      exists  test/unit/
      exists  test/fixtures/
      create  app/models/invoice.rb
      create  test/unit/invoice_test.rb
      create  test/fixtures/invoices.yml
      exists  db/migrate
      create  db/migrate/003_create_invoices.rb
#

なんつーか、このサクサク感がたまりませんな。で、請求書ってどうなってるんだったか (を
ええと payment の方は

  • user_id

で invoice が

  • payment_id
  • unit_price
  • qty

とかでとりあえず。(すんげぇ微妙だけどプロトタイプなのでスルー
下書きが以下

class CreatePayments < ActiveRecord::Migration
  def self.up
    create_table :payments do |t|
      t.column :user_id, :integer    
    end
  end

  def self.down
    drop_table :payments
  end
end

あるいは

yamane@playthings.railsplayground.com [~/ug_proto]# cat db/migrate/003_create_invoices.rb 
class CreateInvoices < ActiveRecord::Migration
  def self.up
    create_table :invoices do |t|
      t.column :payment_id, :integer
      t.column :unit_price, :integer
      t.column :qty, :integer
    end
  end

  def self.down
    drop_table :invoices
  end
end

というカンジで良いのかな。で、とりあえず scaffold でメンテ画面作ってユーザ作っておけばプロトタイプは完成か。でも 5 分ではないな (何

もうちょい

migrate も OK だったので次、なんですがどうしよ

  • Payment な scaffold 作成
  • users にデータ追加

で、ENV['RAILS_ENV'] = 'production' にしておけばいいんだっけ? ま、いいや余計なコトには構わずヤッちまえ。

# ./script/generate scaffold Payment
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/payments
      exists  app/views/layouts/
      exists  test/functional/
  dependency  model
      exists    app/models/
      exists    test/unit/
      exists    test/fixtures/
   identical    app/models/payment.rb
   identical    test/unit/payment_test.rb
   identical    test/fixtures/payments.yml
      create  app/views/payments/_form.rhtml
      create  app/views/payments/list.rhtml
      create  app/views/payments/show.rhtml
      create  app/views/payments/new.rhtml
      create  app/views/payments/edit.rhtml
      create  app/controllers/payments_controller.rb
      create  test/functional/payments_controller_test.rb
      create  app/helpers/payments_helper.rb
      create  app/views/layouts/payments.rhtml
      create  public/stylesheets/scaffold.css
#

あ、よく考えたら users も scaffold しとけば良いの??
って vendor/plugins/login_engine/app みたら user_controller.rb ってのがありますな。でも初期ユーザは手動で作らないと駄目か。とりあえず production にしてみて見えるかどうかテスツ。

公開フォルダにリンクこさえただけではダメな模様。とほほほ、どーやんだっけ。ってどうやらリンクのこさえかたが間違いだった模様。rails 配下の public へのリンクを公開フォルダに作れば良い模様。
って production な DB にテーブルないし。これは migrate すれば良いのか。って

# rake migrate
(in /home/yamane/ug_proto)
The rake task migrate has been deprecated, please use the replacement version db:migrate
#

って言われる始末。面倒だからファイルをコピーしてやれ。

# mv db/sqlite3.production db/sqlite3.production.ORG
# cp db/sqlite3.dev db/sqlite3.production
# 

で、ログイン画面が出ました。ここからユーザ作ってできあがり。先様に連絡を。

追記

よく考えると別に production にしなくても良かったような気が。
でも migrate してて、development から production に切り替える時ってどうやるんだろ。微妙に謎だが調べる時間ナシ。
それにしても SQLite って手軽だなぁ。

さらに

作業しながらナグリ書きしてるから「って」が多い。自分でもアタマに来る位多い。もう少し丁寧に文章を書く練習というか丁寧さを意識して文章書かないと駄目ッス。(とほほ