Ruby on Rails1.2と2.0が混在しているなー ちゃんと分けないと... NEWS2008/10/22 環境http://rubygems.rubyforge.org/wiki/wiki.pl?RubyGemsよりRubyGems?をインストールしておきます。http://gesource.jp/programming/webgen/01.htmlのOne-Click Installerからでもインストールできます。 wget http://rubyforge.org/frs/download.php/5208/rubygems-0.8.11.zip unzip rubygems-0.8.11.zip cd rubygems-0.8.11 ruby setup.rb あら?つながらなくなってますね。上記URLはつながらなくなってますね。ではこちらよりダウンロードします。http://rubyforge.org/frs/?group_id=126 wget http://rubyforge.org/frs/download.php/17190/rubygems-0.9.2.tgz tar xzvf cd rubygems-0.9.2 ruby setup.rb いまは1.0.1ですね。(2007-12-20)ではRailsもインストールしておきましょう。 gem install rails --include-dependencies 最新にする場合は、 gem update rails windowsはRailsインストールを参考に cd H:\ruby\rubygems-1.0.1 ruby setup.rb この後進んで、 As of RubyGems 0.8.0, library stubs are no longer needed. Searching $LOAD_PATH for stubs to optionally delete (may take a while)... ...done. No library stubs found. H:\ruby\rubygems-1.0.1> で終わり。zlib.dllがいる場合があるらしいので、そのときはH:\ruby\binにでもほりこんでおきます。 さてgemがはいったので、railsをいれましょう。 gem install rails --include-dependencies んーSSLEAY32.dllやLIBEAY32.sllがないといわれましたね。OpenSSL for Windowsよりopenssl-0.9.8e-win32-bin_dynamic.zip をダウンロードして、解凍すればありますので、ruby\binにでもほりこんでおきましょう。あっそろそろwindowsがいやになってきた... ん? Installing ri documentation for rake-0.8.1... Installing ri documentation for activesupport-2.0.2... Installing ri documentation for activerecord-2.0.2... 2.0になっていたのか。 ほかにiconvやreadlineは入れておきましょう。 readlineは解凍して、binにreadline.dllをコピーします。でないとruby script/consoleとしても、 c:/ruby/lib/ruby/1.8/i386-mswin32/readline.so: 126: 指定されたモジュールが見つかりません。 - c:/ruby/lib/ruby/1.8/i386-mswin32/readline.so (LoadError) とかってエラーがでます。 ではDEMOを動かしてみましょう。適当なディレクトリで、 rails demo cd demo ruby script/server デフォルトでポート3000をつかってWEBrickが起動しますので、ブラウザから確認してみてください。WEBrickはRubyのみで書かれたWebサーバでRubyとともにインストールされています。ちなみにdemoで ruby script/generate controller コントローラ名 とするとMVCのコントローラが作成されます。コントローラ名は頭大文字後小文字です。そのかなにメソッドをつくり、app/views/コントローラ名/メソッド名.rhtmlをUTF-8で保存すると動きました。http://localhost:3000/コントローラ名/メソッド名 また実行して no such file to load -- sqlite3 ってエラーが出た場合は、 gem install sqlite3-ruby とします。それでもエラーが出る場合は、http://sqlite.org/download.htmlよりsqlite-3_5_5.zipとsqlitedll-3_5_5.zipをダウンロード(windowsの場合) 適当な場所に展開して、同一ディレクトリにコピー後パスを通します。database.ymlの設定がsqlite3になっているので、別のDBに変えてもOKです。 mysqlでも同じようなエラーがでました。leopardの場合は、 env ARCHFLAGS="-arch i386" gem install mysql -- --with-mysql-config=/usr/local/mysql5/bin/mysql_config アップデイトgem update --system gem update ApacheFastCGIApacheのFastCGIを参考に先にいれて、実行したら、 RailsFCGIHandler(NameError) とlog/error_logに出力されていたので、先を参考に(参考http://www.ruby-forum.com/topic/56459 ) gem install fcgi 一応httpdを再起動して、railsのプロジェクトを作ったら、そのアプリケーションの中のpublic/.htaccessを修正します。 #RewriteRule ^(.*)$ dispatch.cgi [QSA,L] RewriteRule ^(.*)$ dispatch.fcgi [QSA,L] また必要に応じて #RewriteBase /test を書き換えましょう。ここで私がはまった愚かなことがあります。いくら動かしても execle() failed: No such file or directory や (2)No such file or directory: FastCGI: と表示され全く動きませんでした。cgiにしても動かない。これはFastCGIの問題じゃないやんかと思い、悩んでいると、publicの中に dispatch.cgi dispatch.fcgi と2つのファイルがあります。cgi? そういえればwindowsでつくったやつをそのままコピーしな。と思い中を覗いてみると、 先頭に #!c:/ruby/bin/ruby なんだこれは... #!/usr/local/bin/ruby に書き換えると動き出しました..... さてrails2を試してみると、ん?今度は Invalid command 'RewriteEngine', perhaps mis-spelled or defined by a module not included in the server configuration なんてエラーがでているな。これはmod_rewriteが入ってなかったので入れました。すると今度は FastCGI: comm with (dynamic) server "/www/public/dispatch.fcgi" aborted: (first read) idle timeout (30 sec) これじゃよくわからんので、わからんときはWEBrickで ruby script/server とするとと、 /usr/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require': no such file to load -- gettext/rails (MissingSourceFile) gettext入ってないないか。入れた覚えはないもんな。では入れましょう。http://rubyforge.org/frs/?group_id=855より wget http://rubyforge.org/frs/download.php/31658/gettext-1.90.0.gem gem install gettext-1.90.0.gem やっと動きました。 さてこのままwebrootにコピーしちゃうと、configとかdbが丸見えなんでそれはいかんでしょうってことで、webrootを仮に/webroot/usera/rootってすると /webroot/usera/rubyを作ってそこに一式をコピーし(仮にプロジェクトをrubytest)、httpd.confに Alias /rubytest/ "/webroot/usera/ruby/rubytest/public/" <Directory "/webroot/usera/ruby/rubytest/public"> Options +ExecCGI AllowOverride all Order allow,deny Allow from all AddHandler fastcgi-script .fcgi </Directory> ってやって、.htaccessのRewriteBaseを/rubytestとしてやりました。 参考:Ruby-GetText-Package MongrelFastCGIは確かに早いが、評判がよろしくない。apache2で動いてあまり変な動きはしてないがちょっと見合わせたほうがよさそうってことで、 MongrelをいれてApacheと連携しましょう。 gem install mongrel --include-dependencies とるすと、linuxなんで、 Select which gem to install for your platform (i686-linux) 1. mongrel 1.1.4 (x86-mswin32-60) 2. mongrel 1.1.4 (java) 3. mongrel 1.1.4 (ruby) 4. mongrel 1.1.3 (ruby) 5. mongrel 1.1.3 (i386-mswin32) 6. mongrel 1.1.3 (java) 7. Skip this gem 8. Cancel installation > 3 Select which gem to install for your platform (i686-linux) 1. fastthread 1.0.1 (mswin32) 2. fastthread 1.0.1 (ruby) 3. Skip this gem 4. Cancel installation > 2 としました。 gem install mongrel_cluster も入れておきます。 ではちょっと起動して見ましょう。 mongrel_rails start -p 8000 -e production -c /webroot/ruby/railstest -d --prefix /railstest 引数の-pはポート、-eはRails environmentなんで指定しなければdevelopment、-cでカレントディレクトリの指定、-dでデーモンで起動、--prefixでurlです。 Rails requires RubyGems >= 0.9.4 (you have 0.9.2). Please `gem update --system` and try again. ん?エラーだ。では指示通りに、 gem update --system gettextは上記のFastCGIを参考にして、入れておきましょう。では再度起動して動きました。 では終了してみましょう。 mongrel_rails stop -P /webroot/ruby/railstest/log/mongrel.pid さて動作したんで、次はリバースプロキシの設定です。mod_proxyでやってみましょう。参考:Apache モジュール mod_proxy httpd.confに ProxyRequests Off <Proxy *> Order deny,allow Allow from all </Proxy> ProxyPass /railstest http://192.168.1.1:8000/railstest ProxyPassReverse /railstest http://192.168.1.1:8000/railstest を追加して再起動です。ではクラスタで複数起動するときは mongrel_rails cluster::configure -N 2 -p 8000 -e production -c /webroot/ruby/railstest -d --prefix /railstest mongrel_rails cluster::start です。apache2.2だと、mod_proxy_balancerが使えるので、参考:Apache モジュール mod_proxy_balancer <Proxy balancer://rails-app/> BalancerMember http://192.168.1.1:8000/railstest loadfactor=10 BalancerMember http://192.168.1.1:8001/railstest loadfactor=10 </Proxy> ってやるとバランサーになります。そういえば、 Ruby version is not up-to-date; loading cgi_multipart_eof_fix ってエラーがでたことがあります。Rubyのバージョンが古いとのこと。あげとくか。
Mongrel HOWTO
Pound + Mongrel + Apache2.0 で Ruby on Rails! LiteSpeed?速いらしいが調査中 Passenger本命はこいつか?Mongrelもいいですよ。 gem install passenger passenger-install-apache2-module インストールするとメッセージが表示されていますので、それにあわせてhttpd.confを修正しましょう。ちなみに下記はleopardで実行した時のメッセージです。 LoadModule passenger_module /Library/Ruby/Gems/1.8/gems/passenger-1.0.1/ext/apache2/mod_passenger.so RailsSpawnServer /Library/Ruby/Gems/1.8/gems/passenger-1.0.1/bin/passenger-spawn-server RailsRuby /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby <VirtualHost *:80> ServerName www.yourhost.com DocumentRoot /somewhere/public </VirtualHost> またRailsをさらに加速するテクノロジー「Ruby Enterprise Edition」なんてなもんも あるようで、1.9でRailsが動いてくれるまでなんとかしのぐか。 Passenger users guide RailtiesRailsを利用するためのユーティリティです。 script/generate ジェネレータ ひな形作成 model モデル scaffold モデル名 コントローラ名 アクション名 # モデル名必須 これでCRUD操作ができる controller コントローラ migration マイグレーション migrateテーブル作成 class CreateProducts < ActiveRecord::Migration def self.up create_table :products do |t| t.column :title, :string, :limit=>100, :null => false t.column :description, :string t.column :image_url, :string, :limit=>200, :null => false t.column :price, :integer, :null => false end end def self.down drop_table :products end end カラム追加 class AddDateAvailableToProduct < ActiveRecord::Migration def self.up add_column :products,:date_available,:datetime end def self.down remove_column :products,:date_available end end developmentではなくproductionに適用したい場合は、EclipsのRakeタスクの場合、直接 RAILS_ENV=production db:migrate と打ち込んでリターンで実行されます。 Ruby on Rails で使えるデータ型 database.ymlどんな記述が追加出来るか調べていました。 development: adapter: mysql database: hoge_development username: hogeuser password: hogepass host: 192.168.1.1 port: 3306 encoding: utf8 timeout: 5000 environment.rb本番にDBを切り替える# ENV['RAILS_ENV'] ||= 'production' を ENV['RAILS_ENV'] ||= 'production' としてやります。 productionに設定すると、サーバー(httpd,mongrel等)を再起動しないとコードの変更は反映されないので、注意 ActiveRecord?参考:RubyOnRails を使ってみる 【第 3 回】 ActiveRecord 項目命名規約datetime _atで終わる date _onで終わる 外部キー ターゲットのクラス名を小文字に変えて_idをつける テーブル名を変更するdef self.table_name() "tablename" end もしくは set_table_name "tablename" findidでの検索では見つからない場合、エラーとなるので捕捉してやる必要があります。 product = Product.find(params[:id]) rescue ActiveRecord::RecordNotFound flash[:notice] = "そんなIDはない" とか、 product = Product.find(params[:id]) rescue => ex flash[:notice] = ex.message とか。 トランザクションActiveRecord::Base::transaction() do rascue end って書き方もできるのか.. http://underrails.seesaa.net/article/54762314.html has_manyべたで書いた場合 has_many :data1, :class_name => "Data1", :finder_sql => 'select data1.* from data1,data2 where data2.id = data1.koumoku_id and data1.id = #{id}' ダブルクォーテーションではなくシングルクォーテーションで またファインダメソッドを使って has_many :specific_lineitems, :class_name => "lineitem" do def get(id) find :all,:conditions=>['order_id = ?',id] end end とかってしてやって、 p order.specific_lineitems.get(hoge) としてやることもできる。 p order.lineitems.find(:first,:conditions =>["order_id=?",hoge]) でいいのですが。なんか変な感じだと思っていると、order.findで子のlineitemsの条件が書き方がわからんからだー
もちろんWHERE order_id = ?ではなく、LEFT OUTER JOINに。
仮に書けたとして、includeは書けるのか?
この辺は再調査だな。でもこんなの見つけてしまったということはだめなのか? has_many :lineitems,:include=>"lineitem",:order => "lineitems.cdkoukou" としてやればできた。このorderは複数なのか。 has_manyでテーブル関連付けをしたときのDB更新 find_by_sql@table1 = Table1.find_by_sql("select table2koumoku1 from table2") このfind_by_sqlはTable1と関係ないtable2でのsqlを使っても取得できた。 <% for table1 in @table1 -%> <tr> <td><%= h(table1.table2koumoku1) %></td> </tr> <% end -%> これは逃げ道になりそう?またパラメータを渡す場合は、 aaaa = "11" @table1 = Table1.find_by_sql("select table2koumoku1 from table2 where table2koumoku1 = ?",aaaa) とか @table1 = Table1.find_by_sql(["select table2koumoku1 from table2 where table2koumoku1 = :id and table2koumoku2 = :id2",{:id => params[:id],:id2 => params[:id2]}]) 他に params = {} params[:para2] = "2" params[:para1] = "1" find(:all,:conditions => ["code_id = :para1 and image_url = :para2",params],:order => "title") とすると SELECT * FROM `products` WHERE (code_id = '1' and image_url = '2') ORDER BY title となるので、動的にSQLも書けることでしょう。 connection.select_allもうひとつの逃げ道として(逃げてばっかりですが..)、コントローラで @datas = Table1.connection.select_all("select * from table2") として、 <% @datas.each{|value| -%> <tr> <td><%= h(value['table2koumoku1']) %></td> </tr> <%} -%> destroyとdeleteの違いdeleteはコールバックと検証を迂回していき、直接deleteだけになり、dependentとかもよびだされません。 destroyはすべて呼び出してくれます。ですので通常はdestroyのほうがいいでしょう。 コード管理漢には笑わせてもらいました。 いまこそ ARと外部キーについて考える (舞波) SQL確認ActiveRecord?が生成するSQLは、logディレクトリに出力されています。EclipseですとNTailというプラグインがありますので、 それで確認できます。 リンクRails RecipeBookはてな版(多対多の関連を設定する) ActiveScaffold?優しいRailsの育て方 この本はおもしろかったです。早く2版でないものでしょうか。 GetText?エラーを日本語化したい場合、ActiveHeart?よりこっちみたいな記事があったので、試してみます。 c:\ruby>gem install gettext ERROR: While executing gem ... (Gem::RemoteFetcher::FetchError) 接続済みの呼び出し先が一定の時間を過ぎても正しく応答しなかったため、接続でき ませんでした。または接続済みのホストが応答しなかったため、確立された接続は失敗し ました。 - connect(2) (Errno::ETIMEDOUT) getting size of http://gems.rubyforge.org/Marshal.4.8 ん?なんだ。ファイアーウォールではじかれていたのか。では設定です。 config/environment.rbの最初に $KCODE='u' # u=utf s=Shift_JIS, e=EUC-JP require 'jcode' とし、最後に require 'gettext/rails' 記述します。またapp/controllers/application.rbに init_gettext "hogedom" とテキストドメインの名前を記述しておきます。この名前はDBの項目を日本語化するときにも出てきます。 では翻訳文字を抽出する為にlib/tasksにrakeタスクをつくります。とりあえず名前はgettext.rakeで desc "Update pot/po files." task :updatepo do require 'gettext/utils' GetText::ErbParser.init(:extnames => ['.rhtml', '.erb']) GetText.update_pofiles( "hogedom", #<<<<<<テキストドメインの名前 Dir.glob("{app,config,components,lib}/**/*.{rb,rhtml,rjs,erb}"), "hogedom 1.0.0") #バージョン end desc "Create mo-files" task :makemo do require 'gettext/utils' GetText.create_mofiles(true, "po", "locale") end では実行しましょう。 rake updatepo するとpoディレクトリが作成され、その中にテキストドメイン名のrailsproject.potができました。 これをpo/jaディレクトリを作成して、そこにコピーして、railsproject.poにリネームします。 po/ja/railsproject.po 中を見ると、たとえば #: app/models/product.rb:- msgid "Product|Title" msgstr "" てな感じになっているので、 #: app/models/product.rb:- msgid "Product|Title" msgstr "タイトル" とか日本語を入れてやります。設定後、 rake makemo でエラー表示の時に項目名も日本語化されます。ではコントローラのメッセージは?ということで def create @code = Code.new(params[:code]) respond_to do |format| if @code.save flash[:notice] = 'Code was successfully created.' とかありますが、 flash[:notice] = 'Code was successfully created.' を flash[:notice] = _('Code was successfully created.') にしてやり、po/ja/railsproject.poに #: app/controllers/codes_controller.rb:- msgid "Code was successfully created." msgstr "登録成功!" としてやった後にrake makemoです。ではviewも <p> <%= f.submit 'Update' %> </p> を <p> <%= f.submit _('Update') %> </p> として、po/ja/railsproject.poに msgid "Update" msgstr "更新!" これってmsgidってどこでも使えるですね。 ついでに、 class Code < ActiveRecord::Base validates_presence_of :codekn,:code,:message => "%{fn}は必須!" set_error_message_title("%{record}にエラーがある。", "%{record}に%{num}個もエラーが...") set_error_message_explanation("以下のエラーを確認せよ!", "ちょっとエラーが多いよ....") end とすると、 コードテーブルに2つのエラーが発生しました。 次の項目を確認してください。 * コードを入力してください。 * コード区分を入力してください。 ってメッセージが コードテーブルに2個もエラーが... ちょっとエラーが多いよ.... * コードは必須! * コード区分は必須! Ruby-GetText-Packageとは? デバッグp オブジェクト名 とすると、コンソールに表示されれるので確認 <%= debug(params) %> TIPSとりあえずapp/controllers/コントローラ名_controller.rb class コントローラ名Controller < ApplicationController def メソッド名 @test = "へへっへ" end end メソッド名.rhtml <html> <head> <title>ほほほほー</title> </head> <body> <% 3.times do |count| %> <h1><%= count %>ひっひ-</h1> <%= @test %> <% end %> </body> </html> ここで、JSPみたいにRubyのコードを<%で埋め込んでますが、JSPみたいなもんです。 さてscaffoldをつかったらエラーがでました。Ruby on Rails2.0から変わったんですね。 undefined method `scaffold' for AdminController:Class その対象のプロジェクトのディレクトリで、 ruby script/plugin install scaffolding ruby script/plugin install http://tools.assembla.com/svn/breakout/breakout/vendor/plugins/classic_pagination/ ruby script/plugin install http://tools.assembla.com/svn/breakout/breakout/vendor/plugins/will_paginate/ また登録したとき ActionController::InvalidAuthenticityToken ってでる。これも2.0からで外部から来たリクエストであればはじくようになっているそうなのだが、おそらくscaffoldがCSRFの対策をしてなくて、hiddenを埋め込んでいないからだろう。ってことで、Controllerに skip_before_filter :verify_authenticity_token を追加してやるとskipしてくれます。 また実際に動かしてみると、登録時に日本語で落ちる場合は、 ActiveRecord::StatementInvalid in ... config/database.ymlにencoding:の指定を追加しましょう。dbの文字コードとあわせておきます。Rails2.0からはscaffoldが script/generate scaffold book から script/generate scaffold book title:string price:integer みたいにモデル名に後にフィールド名と:データ形式を追加するんですね。 ん?生成されたコントローラを見ると、 respond_to do |format| format.html # index.html.erb format.xml { render :xml => @books } end ってあります。これって2.0からか。http://wota.jp/ac/?date=20060317#p01を参考に 参考:■[Ruby on Rails]2.0のscaffoldから書き直してみる ルートページの設定config/routes.rbに # You can have the root of your site routed with map.root -- just remember to delete public/index.html. # map.root :controller => "welcome" とかってありますので、 map.root :controller => "login", :action=>"login" とかに変更して、public/index.htmlを消しておきます。 部分テンプレート頭にアンダーバー(_)をつける。 <%= render(:partial => "cartitem",:collection => @cart.items) %> このような場合、_cartitem.html.erbという部分テンプレートをしようすることになる。 またここではcollectionにセットをしている為、_cartitem.html.erbはそのcollectionの要素数分(@cart.items.size)回る。 _cartitem.html.erbではこのcollectionの要素はcartitemでアクセスできる <li><%= h(cartitem.quantity)%>個<%= h(cartitem.price)%>円 <%= h(cartitem.title)%></li> みたいに。このcollectionは他にもobjectとか指定可能 cycle<%= cycle(i, "") -%> とかって書けば、一つとばしに出力されるのかなーと思っていたけど、値が変わる場合はだめでした。
そりゃそうか。 スクリプトrails プロジェクト名 #プロジェクト作成 ruby script/server -e development(test,production) #サーバ起動 ruby script/generate scaffold モデル名 コントーラ名 ※2.0違います。 ruby script/generate ajax_scaffold モデル名 コントーラ名 ajax ruby script/generate controller コントローラ名 #コントローラ作成 ruby script/generate model テーブル名 #モデル作成 単数形で ruby script/destroy ファイル削除 ruby script/runner メソッドをコンテキスト外で動かすことができるみたい。 コールバッグフックdef before_create #保存前にフック def after_create #保存後にフック def before_destroy #削除前にフック チェック必須チェック validates_presence_of :項目 ユニーク validates_uniqueness_of :項目 ここで項目が2つでユニークって場合で,たとえばhoge1の中でhoge2は重複したらだめという場合は、 validates_uniqueness_of :hoge2,:scope => :hoge1 ん?3つの場合はどうすんだ? validates_uniqueness_of :hoge3, :scope => [:hoge1, :hoge2] でいいのか。 数値チェック validates_numericality_of :項目 ActiveRecord::Validations::ClassMethods モデルにエラーを追加する場合model.errors.add_to_base("エラーを追加") collection_select<%= collection_select("user",user.code,@users,"code","name",{:include_blank => true})%> とかしてもうまくselecedがついてくれないので、とりあえず、ApplicationHelper?に def select_ext (strName,strCode,arrData,value,outdata,isBlank) strReturn = '<select id="'+strName+'_'+strCode+'" name="'+strName+'[' + strCode + ']">' if isBlank == true strReturn += '<option value=""></option>' end for oneData in arrData if (strCode == oneData[value]) strReturn += '<option value="'+oneData[value]+'" selected="selected">'+oneData[outdata]+'</option>' else strReturn += '<option value="'+oneData[value]+'">'+oneData[outdata]+'</option>' end end strReturn += "</select>" return strReturn end とかしてviewから呼び出して逃げてます.. はやく調べんと.. codes = Code.find(:all,:order => "id").map {|u| [u.nmname,u.id]} f.select(:code_id,codes,{:include_blank => true}) と思ったらあっさりOK。 codes = Code.find(:all,:order => "id") f.collection_select(:code_id,codes,:id,:code,{:include_blank => true}) もOK。 f.collection_select(:code_id,Code.find(:all,:order => "id"),:id,:code,{:include_blank => true}) でもOK。書式は collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {}) なので、 f.collection_select(:code_id,Code.find(:all,:order => "id"),:id,:code,{:include_blank => true},{"name"=>"hohogee"} ) と指定できる。 collection_selectやselect, Rails のコンボボックス(select)を生成する時の tabindex 属性の指定の仕方について を参照 複数のsubmitボタン (2.0)とりあえず、やってみた。viewで <%= f.submit 'ボタン1',:name=>'aa' %> <%= f.submit 'ボタン2',:name=>'aa2' %> で、controllerで def update unless params[:aa].nil? p "aa != nil"; end unless params[:aa2].nil? p "aa2 != nil"; end ただこれ、disable_withを指定するとparamsにセットされなくなるな。なんでだ?
同一フォームに複数のイメージ送信ボタン 複数モデルの保存 (2.0)では早速サンプルを。ついでに複数ボタンも <% form_tag(:action => 'update1') do %> <% for @code in @codes %> <%= text_field("code[]", 'nmname') %><br> <% end %> <%= submit_tag 'こっちだけ更新',:name=>'aa1' %> <%= submit_tag 'なにもしない',:name=>'aa2' %> <% end %> この2行目でcodeを@codeとインスタンス変数にして、 3行目でcodeに[]をつけてやってます。するとhtmlは <form action="/codes/update1" method="post"> <input id="code_1_nmname" name="code[1][nmname]" size="30" type="text" value="ddd" /><br> <input id="code_2_nmname" name="code[2][nmname]" size="30" type="text" value="bdddd" /><br> <input id="code_3_nmname" name="code[3][nmname]" size="30" type="text" value="cfffff" /><br> <input name="aa1" type="submit" value="こっちだけ更新" /> <input name="aa2" type="submit" value="なにもしない" /> </form> と生成してくれます。ではcontrollerで def update1 #p params unless params[:aa1].nil? params[:code].each{|key,value| Code.update(key,:nmname => value[:nmname]) } end redirect_to :action => 'index' end とすれば更新できます。 params[:code].each{|key,value| Code.update(key,:nmname => value[:nmname]) } は Code.update(params[:code].keys,params[:code].values) と簡単に記述できます。 <% form_for :hoge, :url => {:action => 'update1'} do |f| %> <%= f.text_field :nmname %><br> <% for @code in @codes %> <%= text_field("code[]", 'nmname') %><br> <% end %> <%= submit_tag 'こっちだけ更新',:name=>'aa1' %> <%= submit_tag 'なにもしない',:name=>'aa2' %> <% end %> でhtmlは <form action="/codes/update1" method="post"> <input id="hoge_nmname" name="hoge[nmname]" size="30" type="text" /><br> <input id="code_1_nmname" name="code[1][nmname]" size="30" type="text" value="dddd" /><br> <input id="code_2_nmname" name="code[2][nmname]" size="30" type="text" value="bddddfd" /><br> <input id="code_3_nmname" name="code[3][nmname]" size="30" type="text" value="cfffffa" /><br> <input name="aa1" type="submit" value="こっちだけ更新" /> <input name="aa2" type="submit" value="なにもしない" /> </form> ちゃんとidやnameにhogeがつきました。ちなみにselectの場合は、 <%= collection_select("code[]", 'code',@codes,:code,:nmname) %> でいけるので、同じです。 参考 paginate (1.2)モデルに対しては @pages, @users = paginate(:users, :order_by => 'usercode') とかすればいいのだが、そんな単純なケースでない場合、Paginatorを使うことになる。http://wota.jp/ac/?date=20050629にも書かれていますが、ほんとpaginate_by_sqlてなものがほしいです。 per_page = 5 @tmp = Jikanwari.find_by_sql(["select count(*) as cnt from jikanwari where youbi <> ?","7"]) count = @tmp[0].cnt.to_i @pages = Paginator.new(self, count, per_page, @params['page']) @jkanwaris = Jikanwari.find_by_sql(["select * from jikanwari where youbi <> ? LIMIT ? OFFSET ?", "7", per_page, @pages.current.to_sql[1].to_i]) でviewに <%= pagination_links(@pages) %> paginate(2.0)classic_pagination を will_paginateに置き換えてみた。 フィルターbefore_filter :メソッド名1 :except => :メソッド2 メソッドの呼び出し前にメソッド名1を呼び出します。ただしメソッド2は除きます。 フォームヘルパー
コントローラ名取得<%= controller.action_name%> Ajaxまずjavascriptsを使えるようにしておきます。javascriptsはpublic/javascriptsにいます。html.erbを開いて <%= javascript_include_tag :defaults %> としておくと、 <script src="/javascripts/prototype.js?1204131898" type="text/javascript"></script> みたいに生成されます。そして、 <% form_tag(:action => 'add_to_cart',:id=>product) do %> とかなっているところを <% form_remote_tag :url=>{:action=>:add_to_cart,:id=>product} do%> とform_remote_tagに変更します。htmlは <form action="/store/add_to_cart/3" method="post" onsubmit="new Ajax.Request('/store/add_to_cart/3', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this) + '&authenticity_token=' + encodeURIComponent('da20420b9451c0hohohohohohohoho')}); return false;"> とできてます。このAjax.Requestはprototype.jsですね。parameters:Form.serialize(this)になっているので、formの要素を/store/add_to_cart/3に 送ってくれます。で、store_controllerのadd_to_cartメソッドが実行されますが、レンダリングでhtml.erbからrjsにします。このRJSはおもしろいので、 後でちゃんと勉強するとして、add_to_cart.rjsの中身は page.replace_html("cartid",:partial=>"cart",:object=>@cart) とした場合、雰囲気はrenderに似ていますが、要は部分テンプレートcartにあるcssのidがcartidの要素を置き換えてくれます。 @cartは部分テンプレートで使うオブジェクトになります。 ということは、store_controller#add_to_cartのレンダリングはadd_to_cart.rjsをつかってidの中身をおきかえてくれるんですね。 こりゃ便利!さらにデバッグはfirebugを使って、NetのXHRを選択すれば、追うことができます。 ajax_scaffoldを使う場合 gem install ajax_scaffold_generator RJShtml.erbを <%= javascript_include_tag :defaults %> <div id="hoge"> hoho </div> として、pageをrjsに書いてどうなるかみてみます。 <%= javascript_include_tag :defaults %> をしておくと、public\javascripts配下のjsをインクルードしてくれてます。 <script src="/javascripts/prototype.js?1204131898" type="text/javascript"></script> <script src="/javascripts/effects.js?1204131898" type="text/javascript"></script> <script src="/javascripts/dragdrop.js?1204131898" type="text/javascript"></script> <script src="/javascripts/controls.js?1204131898" type="text/javascript"></script> <script src="/javascripts/application.js?1203128030" type="text/javascript"></script> 後ろについている?1203128030は勝手につきます。おそらくブラウザにキャッシュされるのを防ぐためでしょう。
参考: セッションをDBにrake db:sessions:create とすると create db/migrate/XXX_create_sessions.rb と作成されるので、 rake db:migrate でsessionsテーブルができてます。そしてconfig/environment.rbを開いて # config.action_controller.session_store = :active_record_store を config.action_controller.session_store = :active_record_store としてやります。さてサーバ再起動で、 c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:478: in `const_missing': uninitialized constant CGI::Session::ActiveRecordStore (NameError) from c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/session_management.rb:24: in `const_get' from c:/ruby/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/session_management.rb:24:in `session_store=' ってエラーが出た... なんじゃ んー ではactiverecodeをつかってるいんだろうから、config/environment.rbのはじめのほうに require 'active_record' を追加。どうかな?おっ動いた!では実際にアプリを動かしてみると、 ActionController::InvalidAuthenticityToken in Store#index No :secret given to the #protect_from_forgery call. Set that or use a session store capable of generating its own keys (Cookie Session Store). んー ではメッセージにしたがってActionController?を見てみましょう。 protect_from_forgery # :secret => '11771fd07d754cc5380bdhohohhhoh' これのとことか。コメントをはずしてやって protect_from_forgery :secret => '11771fd07d754cc5380bdhohohhhoh' すると動き始め、sessionテーブルを覗くと保存されています。 消したい場合は、 db:sessions:clear で Shift-JISShitf-JISにこだわっているわけではなく、他の文字コードを使う場合は、どうするのかを調べていた。仮にDBをsjisにした場合、database.ymlに encoding: sjis を追記した。またenvironment.rbに $KCODE = 's' を追加してみたが、文字化けは変わらなかったので、 application.rbを class ApplicationController < ActionController::Base # Pick a unique cookie name to distinguish our session data from others' session :session_key => '_rubytest_session_id' before_filter :set_charset private def set_charset headers["Content-Type"] = "text/html; charset=Shift-JIS" end end にすると表示されるようになった。しかし、これでやるとmodels/hogetable.rbで validates_presence_of :title,:message => "に空はだめ" とか日本語にすると落ちてしまうので、before_filterをやめて、environment.rbの最後に $KCODE = 'SJIS' ActionController::Base.default_charset = 'Shift_JIS' としてやると日本語で出力されました。出力はされましたが、こんなことを全てに書いていてはどうしようもありません。 RUBY_HOME\gems\1.8\gems\activerecord-1.15.3\lib\active_record\validations.rb にメッセージがあり、 @@default_error_messages = { :inclusion => "is not included in the list", :exclusion => "is reserved", :invalid => "is invalid", :confirmation => "doesn't match confirmation", :accepted => "must be accepted", :empty => "can't be empty", このあたりを書き換えれば、いけそうなんですが、それもどうかと思い、調べていると、new_errorsってなものがありました。http://wiki.rubyonrails.com/rails/pages/HowToWritePluginToModifyRailsCoreを参考に ruby script/generate plugin new_errors を実行し、 RUBY_HOME\depot\vendor\plugins\new_errors\init.rb に、 require 'new_errors' を追加して、 RUBY_HOME\depot\vendor\plugins\new_errors\lib\new_errors.rb に module ActiveRecord class Errors @@default_error_messages[:inclusion] = "is not included in the list ignoramus." @@default_error_messages[:exclusion] = "is reserved. Pay attention!" @@default_error_messages[:invalid] = "is invalid, moron.う" @@default_error_messages[:confirmation] = "doesn't match confirmation. Pick something that does!" @@default_error_messages[:accepted ] = "must be accepted or it will not work." @@default_error_messages[:empty] = "空は駄目よ" @@default_error_messages[:blank] = "ブランクはいかん" @@default_error_messages[:too_long] = "長すぎ (max is %d characters). IT IS TOO LONG!!!" @@default_error_messages[:too_short] = "短すぎ (min is %d characters). t.o.o.s.h.o.r.t." @@default_error_messages[:wrong_length] = "is the wrong length (should be %d characters). I'm sorry. That is an incorrect response." @@default_error_messages[:taken] = "has already been taken by your mom." @@default_error_messages[:not_a_number] = "数字じゃないやん. Numbers are things like 01234 ok?" end end を追加して、修正して実行し、WEBrickを再起動すると、 @@default_error_messages[:blank] = "ブランクはいかん" で new_errors.rb:10: Invalid char `\203' in expression (SyntaxError) とエラーで立ち上がりません。んー UTF-8で保存するととりあえず、立ち上がりましたが、その場合は文字化け... では RUBY_HOME\gems\1.8\gems\activerecord-1.15.3\lib\active_record\validations.rb ではどうなんだろうと思い修正すると、うまく表示された.... 当分解決方法が見つかるまではこれでいこう... あとは 4 errors prohibited this product from being saved There were problems with the following fields: を何とか日本語にせんと。ん?Shift-JISからずれてきているような気が。あれ?http://jp.rubyist.net/magazine/?0012-RubyOnRailsやhttp://www.hackmylife.jp/archives/rails/を参照させていただくとActiveHeart?なるものがあるではないか。
こいつをvendor\plugins\active_heartにコピーして動かすと、あー日本語になった。もしやvendor\plugins\active_heart\lib\active_record_messages_ja.rbをShift-JISにすればいけるのかなと思い、やってみましたが、エラーで立ち上がりませんでした... class Product < ActiveRecord::Base set_field_names :title => 'タイトル', :description => '説明', :image_url =>'イメージURL',:price => '価格' とかしてやると、(UTF-8で保存)、エラー時の項目名は、無事日本語になりました。リスト(list.rhtml)の方はどうかと思って見てみると、変わってないやん... そりゃそうか。 column.human_name でタイトル表示しているからでした。 Product.human_attribute_name(column.human_name) あれ?日本語化されんぞ? active_record_messages_ja.rbを見ていると、 def human_attribute_name(attribute_key_name) if @field_names && @field_names[attribute_key_name] @field_names[attribute_key_name] else _human_attribute_name(attribute_key_name) end end の _human_attribute_name(attribute_key_name) に入ってる。ん?human_name? これって、先頭が大文字になっているからか。では、 Product.human_attribute_name(column.name) にしてやれば、うまくタイトルが日本語で出力されました。さてこうなったらnew.rhtmlや、edit.rhtmlもやってしまいましょう。ん? edit.rhtmlを見ると、 <%= render :partial => 'form' %> となってます。この:partialは部分テンプレートなので、ということはアンダーバーをつけた_form.rhtmlがいるはずなので、覗いてみると、げっ!ここはハードコーディングか... <%= Product.human_attribute_name("title") %> に変更しました。new.rhtmlも<%= render artial => 'form' %>になっているので、かってに直っていることでしょう。 複数形の確認Loading test environment (Rails 2.0.2) >> "book".pluralize "book".pluralize => "books" >> "books".singularize "books".singularize => "book" YAMLYAMLを読み込む場合 yamlfile = YAML::load(File.open('hoge.yml')) 二重送信防止disable_with でボタン押下後、表記がかわる。たとえばボタン名称は検索だけど、 クリックすれば、処理中に変わる。 <%= submit_tag '検索',:name=>:seek,:disable_with=>"処理中..." %> ただし、paramsには params[:seek]に'検索'って文字列がはいっていたが disable_withをつけるとそもそもparams[:seek]がない。んー Oraclehttp://wiki.rubyonrails.org/database-support/oracle Mongrel Time out朝webサーバにつなぐとまったくつながらず。Mongrelを再起動するとつながったのですが、production.logを見てみると Status: 500 Internal Server Error Mongrel timed out this thread: shutdown apacheは [Wed Apr 01 10:24:03 2008] [error] [client 192.168.1.1] proxy: error reading status line from remote server 127.0.0.1 [Wed Apr 01 10:24:03 2008] [error] [client 192.168.1.1] proxy: Error reading from remote server returned by /hoge とエラーが発生しています。
どうも
Rails + MySQL (+ Mongrel?) でDB接続の通信が無い状態が続くとデッドロックする。や
MySQLのinteractive_timeoutぽいのですが、MySQLのinteractive_timeoutとwait_timeoutに関係がありそうです。 @@verification_timeout = 0 になっていたんで、config/environment.rbに ActiveRecord::Base.verification_timeout = 14400 を追記してます。mysql側は show variables; で確認すると、interactive_timeout、wait_timeoutともに28800でした。 mysqlのmy.cnfに [mysqld] wait_timeout=31536000 interactive_timeout=31536000 とすれば期間を延ばせるんですが、これは最終手段だよな~ 普通再度コネクトしなおすだけでいいような気がするんですが。 render、redirect_toの違い単純にフォワード、リダイレクトだと思う。 リダイレクトとフォワードの違いを知る 未解決class_evalactive_record_messages_ja.rbで使われていたのですが、? datetimeが化ける登録は普通にできるのですが、product.send(column.name)で表示してみると、そこだけ化けてしまいます。ブラウザの文字エンコーディングをshiftjisにしてみると見えるが、他の項目が化けてしまってます。正しい表示は、 Sun Mar 12 00:55:00 東京 (標準時) 2006 とりあえずかっこ悪いので、strftime("%Y/%m/%d %H:%M:%S")で逃げてます。 Mysql::Error: Lost connection to MySQL server during query:たまにこのようなエラーがでる。とりえあず gem install mysql としていれてみた。 ERROR: Error installing mysql: ERROR: Failed to build gem native extension. ってエラーが出る場合は、 gem install mysql -- --with-mysql-dir=/usr/local/mysql とかにしてみよう。
Lost connection to MySQL server during query TODO早くext?と連携させたい~errors.rejecterror_messages_forの編集方法 redMineプロジェクト管理ソフトウェアだそうです。ソースを見せてもらって勉強させてもらおう Ruby on Railsで作られたプロジェクト管理ツールredMineを使ってみよう リンクapi 参考書籍RailsによるアジャイルWebアプリケーション開発 コメント
|