ActiveSalesforce を使ってみたメモ
http://activesfdc.rubyforge.org/ を少し使う機会があったので、そのメモを。
ちなみに、Salesforce の知識はほぼ無い状態で触ってますのであしからず・・・。
なお、rails のバージョンは 2.3.5 です。
Setup と HelloWorld みたいなもの
1. install
公式の通りに
$ gem install activerecord-activesalesforce-adapter
とすると、activerecord-activesalesforce-adapter-2.0.0 がインストールされます*1が、
これだとrails 2.3.5ではパッチ(http://timothynjones.wordpress.com/2008/12/03/patching-activesalesforce-for-rails-222/)を当てないと正しく動きません*2。
git(GitHub - oldfartdeveloper/activerecord-activesalesforce-adapter: An ActiveRecord adapter for the Salesforce.com API)には、
gem install で入るものより新しい activerecord-activesalesforce-adapter-2.2.2 があり、
こちらの場合はパッチを当てる必要はありませんでした。
インストール方法は、上記ページでも確認できますが、
$ git clone git://github.com/oldfartdeveloper/activerecord-activesalesforce-adapter.git
$ cd activerecord-activesalesforce-adapter/
$ gem build activerecord-activesalesforce-adapter.gemspec
$ gem install activerecord-activesalesforce-adapter-2.2.2.gem
これでインストールできます。
2. config/database.yml
development: adapter: activesalesforce username: <salesforce-username> password: <salesforce-password><salesforce-security_token>
password は、「salesforceにログインするときのパスワード」と「セキュリティトークン」を隙間無く並べた文字列です。
また、gitのページでは上記の他に「url:」の項目が説明されていますが、これは記述しなくても動きます。
記述の有無による違いはわかりませんorz
3. モデルを作ります
$ ruby script/generate model Account ―skip-migration
公式でもgitでも書いてない気がしますが、作らないと動きませんでした。
(作らなくても良い方法があるなら教えて下さいorz)
4. 適当なコントローラで Account.all とかやるとデータが取れます
リレーションの無いfind
Salesforce はAPIで叩く際には、カラム名が「__c」付きになるっぽいので、そこは気をつける必要があります。
# column_a と column_b で引っかける Account.find(:first, :conditions => ["column_a__c = ? AND column_b__c = ?", param_a, param_b]) # こっちの書き方でも動きます Account.find_by_column_a__c_and_column_b__c(param_a, param_b)
で、ここがちょっと微妙なところですが、単に Account.all としても、最大200件しか取ってきません。
でも、limit を大きく設定してあげると200件以上でも取ってきてくれます。
(内部的には、200件ずつループを回して取ってきているようですが。)
# Account に500件のデータが入っていた場合 account = Account.all p account.length # --> 200 account = Account.find(:all, :limit => 1000) p account.length # --> 500
リレーション(belongs_to, has_many)
belongs_to, has_many は普通に使えます。
しかも、自分でモデルに書かなくても、勝手に作ってくれます。
# log/development.log Processing AccountsController#index (for ***.***.***.*** at 2010-06-01 13:24:35) [GET] Created one-to-one relationship 'master_record' from Account to Account using master_record_id Created one-to-one relationship 'parent' from Account to Account using parent_id Created one-to-one relationship 'owner' from Account to User using owner_id Created one-to-one relationship 'created_by' from Account to User using created_by_id Created one-to-one relationship 'last_modified_by' from Account to User using last_modified_by_id Created one-to-many relationship 'account_contact_roles' from Account to AccountContactRole using account_id Created one-to-many relationship 'histories' from Account to AccountHistory using account_id ...
見方としては、
Created one-to-<has_manyならmany / belongs_toならone> relationship '<リレーション名>' from <リレーション元モデル名> to <リレーション先モデル名> using <foreign key>
なので、
例えば、上から3つ目の「Created one-to-one relationship 'owner' from Account to User using owner_id」は、
class Account < ActiveRecord::Base belongs_to :owner, :class_name => "User", :foreign_key => "owner_id" end
と同じで、Account.first.owner とかで使えます。
また、一番下の「Created one-to-many relationship 'histories' from Account to AccountHistory using account_id」は、
class Account < ActiveRecord::Base has_many :histories, :class_name => "AccountHistory", :foreign_key => "account_id", :dependent => :nullify end
と同じで、やはり Account.first.histories で使えます。
上のような勝手に作ってくれるリレーションも使えますが、
自分でモデルに書いても正しく動きます。
(foreign_key などにはやはり API名を指定する必要があります)
ただし、SOQLでは、「モデル名__r.カラム名」とかでリレーション先のカラムを条件式に入れたりできるようですが、
これはActiceSalesforceでは使えないようです?*3
例えば、Account と MyCustomObj に 1 対 多 のリレーションが張られているとします。
Account の column1 が 指定した値の MyCustomObj を取得したい場合、
SOQL的にconditions を書くとたぶん下のようになります。
(Salesforce全然わかってないので、間違ってたらごめんなさい。。。)
MyCustomObj.find(:all, :conditions => ["MyCustomObj__r.column1 = ?", column1_param])
でも、これは動きません。
ライブラリの中身を少し見ましたが、別テーブルへのエイリアスは削除しているっぽいです。
# /usr/local/lib/ruby/gems/1.8/gems/activerecord-activesalesforce-adapter-2.2.2/lib/active_record/connection_adapters/activesalesforce_adapter.rb の 308, 309行目 # strip away any table alias column_name.sub!(/\w+\./, '')
この column_name に上でいうと「MyCustomObj__r.column1」が入ってくるので、
column_name はただの「column1」になり、MyCustomObj には column1 というカラムはないので、
そんなカラム無いよということでエラーになってしまいます。
Column not found for #{column_name}!
これが上手いこと動くととても使いやすい気がするんですがね。。。
insert
これも普通に動きます。
newして値をセットして、saveするだけです。
(値をセットする際に、各カラム名をAPI名にしないといけない点だけ注意が必要です)
account = Account.new
account.column1__c = value1
account.column2__c = value2
...
account.save!
とりあえず、実際に使ってみたのはこれくらいですが、
「update」とか「delete」も定義されてるので、同様に使えるのではないかと思います。
参考
- ActiveSalesforce 公式: http://activesfdc.rubyforge.org/
- ActiveSalesforce patch for rails2.3.5: http://timothynjones.wordpress.com/2008/12/03/patching-activesalesforce-for-rails-222/
- 参考ブログ1: http://htakeuchi.offtheball.jp/archives/18
- 参考ブログ2: 脈絡のない備忘録: ActiveSalesforce
- Salesforce – Web Services API Developer’s Guide: Salesforce Developers
- git: GitHub - oldfartdeveloper/activerecord-activesalesforce-adapter: An ActiveRecord adapter for the Salesforce.com API