【Apex】スケジュールを操作する
Apexコードを使ってスケジュールの作成・削除を行うことが出来ます。
これらを使えば、特定のクラスが呼び出された後にスケジュールをセットしたり削除したりすることが出来ます。
サンプルコード
CreateSchedule
クラスを呼び出すと、ジョブ名「3時のおやつ」で2016年中毎日15時にScheduledTest
クラスを呼び出すスケジュールが作成されます。
global class CreateSchedule { public static void execute(){ String jobName = '3時のおやつ'; // 2016年毎月毎日15時(年は省略可) String jobTime = '0 0 15 * * ? 2016'; // スケジュールを作成 System.schedule(jobName, jobTime, new ScheduledTest()); } }
今回は開発者コンソールから呼び出せるクラスを書いてみました。
開発者コンソール>Debug>Open Execute Anonymous Window
にアクセスし、下記のコードを記述してExecute
をクリックしてください。
CreateSchedule
クラスが呼び出されます。
CreateSchedule.execute();
スケジュールが作られたかどうかを確認するには、
設定>ジョブ>スケジュール済みジョブ
にアクセスしてください。作成されたスケジュールが一覧で表示されています。
毎日15時になるとScheduledTest
クラスが呼び出されます。
ただ毎日呼び出されると鬱陶しいので、呼ばれたらセットされたスケジュールを消すようにしてみました。
このクラスが呼ばれると、セットされたスケジュールが消され、コンソールにメッセージが表示されます。
global class ScheduledTest implements Schedulable { global void execute(SchedulableContext sc) { String jobName = '3時のおやつ'; // スケジュールオブジェクトからレコードを取得 List<CronTrigger> ct = [SELECT Id FROM CronTrigger WHERE CronJobDetail.JobType = '7' AND CronJobDetail.Name = :jobName LIMIT 1]; // スケジュール削除 System.abortJob(ct[0].Id); System.debug('今日のおやつはカールだよ'); } }
このスケジュールクラスは特殊で、Schedulable
インターフェースを実装していたりします。スケジュールオブジェクトにアクセスするSOQL文もかなり特殊ですよね。
これらは決まった様式なので、最初の内はあまり深く考えなくてもいいかもしれません。 とりあえずはこの様式に当てはめて、自分の行いたい処理を書けばOKだと思います。
参考
おまけ
スケジュールの管理画面を作成されている方がおられました。 ここまでいけばかなりユーザも使いやすいですね。
【Apex】クラス呼び出し後の画面遷移 (PageReference型の使い方)
クラス呼び出し後の画面遷移の仕方がよくわからなかったので調べてみました。
サンプルコードを使って、PageReference
型の簡単な使い方を解説します。
VisualForceページ_Page1
コントローラにJumpTest
を指定し、ボタンでjump
メソッドを呼び出します。
<apex:page controller="JumpTest"> <h1>ここはPage1です</h1> <apex:form > <apex:commandButton action="{!jump}" value="Page2へジャンプ!" /> </apex:form> </apex:page>
Apexクラス_JumpTest
JumpTest
クラスの中に、戻り値PageReference
型のjump
メソッドがあります。
メソッドの最後にreturn
でVisualForceページPage2
を返します。
ここで指定した画面に遷移します。
因みにreturn null
だと元の画面に遷移します。(今回で言うとPage1)
public class JumpTest(){ public PageReference jump(){ return Page.Page2; } }
VisualForceページ_Page2
<apex:page> <h1>ジャンプ成功!ここはPage2です!</h1> </apex:page>
Google Chromeでレポート作成がうまくできなかった話
なかなか同じ状態の人はいないと思うのですが、SalesForceのレポート作成が出来ない現象が起こりハマってしまったのでメモ。
すべてのタブ>レポート
にアクセスしてレポートを作成しようと思ったら、ページ左部のフォルダの部分が延々とダウンロード中で、先に進めなくなりました。
そこから新規レポート
にアクセスして作成ボタンを押してもエラー。
なんじゃこりゃ?と色々検索しても解決策が見つからず。 諦めかけてた時に、ひょっとしたらブラウザが悪さしてるのかな?と思いIEで立ち上げると正常表示されました!(使用していたブラウザはGoogle Chrome)
ここでさらに閃き、ひょっとしたらプラグインが何か悪さしてるんじゃ!?と思いインストールしてるプラグインを見てみると怪しいモノが。
これを無効にすると・・・
表示された!
最初からブラウザを変えてやればすぐ気が付いたんでしょうが、激ハマりしてしまいました。 今後Webでこういうことがあった場合は、まずブラウザを疑ってみるという考え方を身に付けようと思います。
因みに Adblock Plus 1.11 に変更したら問題は起こりませんでした。
【Apex】DB操作を取り消す方法(ロールバック)
データベースへの更新を取り消すロールバックをApexで実装したかったので、調べた結果をまとめたいと思います。
ついでにその際に起こった欠番現象にも少し触れています。
サンプルコード
複数のオブジェクトを更新するサンプルコード。
try
文で一つでもDmlExceptionのエラーがあると、catch
文に移動してロールバックポイントまで戻ります。
今回のサンプルではaccount
もしくはcampaign
のinsert
がどちらか一方でもDmlExceptionを引き起こした場合、両方のインサートが取り消されます。
Account account = new Account(Name = 'aaa'); Campaign campaign = new campaign(Name = 'bbb'); // ロールバックした際に戻るポイント Savepoint sp = Database.setSavepoint(); try{ insert account; insert campaign; }catch(DmlException e){ // 引数に戻るポイントを指定 Database.rollback(sp); }
欠番の可能性
オブジェクトのカラムに自動連番がある、かつロールバックが何回か発生した後でinsert
に成功した場合には番号に抜け(欠番)が生じる可能性があります。
例:
1回目
insert account
=> 成功 ,insert campaign
=> 失敗ロールバック実行 => レコード登録取り消し
2回目
insert account
=> 成功 ,insert campaign
=> 成功レコード登録成功
結果
Account
オブジェクト
No. | Name |
---|---|
2 | aaa |
Campaign
オブジェクト
No. | Name |
---|---|
1 | bbb |
このようにロールバックをしていても、Account
オブジェクトレコードの番号は2で採番されてしまいます。
なんか気持ち悪い・・・。(レコードはちゃんと一個しかないんですが)
ただ、それらは気にするものでもないという意見がこちらに書かれているので、僕はそれを見習おうかと思います。 気になる方は一度見てみてください。
その他ロールバックの詳しいことは下記の参考サイトが詳しいです。
参考
【Apex】メール送信機能 (SingleEmail)
はじめに
仕事で触る機会があったので、Apexコードを使用したメール機能のサンプルを記事にしたいと思います。
ワークフロー機能等では出来ない複雑な条件時のメール送信も、ApexトリガやApexスケジュールなどと併用することで可能になります。
※今回紹介しているのはSingleEmailMessage
と呼ばれる、一人に対して一件メールを送る方法です。
for文等を使えば複数の人にメールを送ることもできますが、ガバナ制限により現在は一度のメソッド実行で10人まで、一日あたり1000件しか送れないみたいなので注意。 詳細は下記参照。
コードサンプル
- Apexクラス_SendMail
一番単純なメール送信機能の例。工夫すれば、取引先責任者オブジェクトなどからselect文で値を取り出し、for文などで取り出した人全員にメールを送るなんてこともできます。(ただし先ほども述べた通り、一度の呼び出しで10人まで)
public with sharing class SendMail { public void SendMail() { Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage(); // ここであて先を指定 mail.setToAddresses(new String[]{'fuga@fugafuga.co.jp'}); // ここでCC送り先を指定 mail.setCcAddresses(false); // こでBCC送り先を指定 mail.setBccSender(false); // ここで送信元を指定 mail.setReplyTo('hoge@hogehoge.co.jp'); // ここで送信元名前を指定 mail.setSenderDisplayName('管理者'); // 必要に応じて電子メールにsalesforce.comのメールの署名を追加します。 // Apexコードを実行しているユーザのメールアドレスが使用されます。 mail.setUseSignature(false); //ここで題名を指定 mail.setSubject('ここに題名を入力'); //ここで本文を指定 mail.setPlainTextBody('ここに本文を入力'); // ここで送る Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail }); } }
- Visualforceページ_SendMail
Apexクラス_SendMailを実行する為の画面を作成します。今回はボタンを押すとSendMailメソッドが実行されるという仕組みになります。
<apex:page controller="SendMail"> <apex:form > <apex:commandButton action="{!SendMail}" value="送信"/> </apex:form> </apex:page>
※Sandbox使用時の注意点
Sandbox環境の場合はメールの設定をしないと送信ができないみたいです。 しかもリフレッシュするとデフォルトでアクセス権限なしになるので毎回設定が必要らしい。
メール管理 > 送信 > アクセス権 > すべてのメール
下記エラーが出た場合は設定を変える必要があります。
NO_MASS_MAIL_PERMISSION
https://odekakeshimasyo.io/salesforce-no_mass_mail_permission.html
Sandbox環境時にWeb to リードでレコードが登録できない問題
設定 > カスタマイズ > リード > Web-to-リード >Web-to-リードフォームの作成
リードオブジェクトに登録したい情報を
選択済みの項目
に入れていきます戻りURL
にフォームの送信ボタンを押した後に遷移するページのURLを入れます作成ボタンを押すとHTMLコードが生成されます
ここまでが通常の手順。
ここからがSandbox環境独自の手順。
生成されたコードのform
タグ内の送信先URLを一部変更する必要があります。
www
=>test
<!-- 修正前 --> <form action="https://www.salesforce.com/servlet/servlet.WebToLead?encoding=UTF-8" method="POST"> <!-- 修正後 --> <form action="https://test.salesforce.com/servlet/servlet.WebToLead?encoding=UTF-8" method="POST">
これでリードオブジェクトにレコードが登録されるはずです。
ていうかこれは生成時に正確に紐づくようにしといて欲しいです…。
参考
お気に入り機能サンプル②(完結)
引き続き、Railsでお気に入り機能のサンプルを作成していきます。
前回は各ユーザが持っているお気に入り一覧を表示させるところまで作成しました。
今回はログインしたユーザがお気に入りの本を登録・削除する、という仕上げの部分を行っていきます。
コントローラ
まずコマンドラインからfavorites
コントローラーを作成します。
rails g controller favorites
次にお気に入りを登録するcreate
、お気に入りを削除するdestroy
アクションを記述します。
セッションに格納したログインユーザのIDと、本一覧画面から選んだ特定の本のIDを初期値として新しいレコードを作ることで、ユーザ別のお気に入りを登録できる様になります。
お気に入りの削除は、ユーザ別のお気に入り一覧(ユーザ詳細画面内)から特定のお気に入りを選びdestroy
メソッドを使うことで可能になります。
- app/controllers/favorites_controller.rb
#お気に入り登録用アクション def create @user_id = session[:id] #ログインしたユーザのID @book_id = Book.find(params[:id]).id #特定の本のID #book_idに@book_id、user_idに@user_idを入れて、Favoriteモデルに新しいオブジェクトを作る @favorite = Favorite.new(book_id: @book_id, user_id: @user_id) if @favorite.save #保存に成功した場合、本一覧画面に戻る redirect_to books_path end end #お気に入り削除用アクション def destroy @favorite = Favorite.find(params[:id]) if @favorite.destroy #削除に成功した場合、ログインしているユーザの詳細画面に戻る redirect_to user_path(session[:id]) end
ルーティング
先ほど作成したfavorites
コントローラと各アクションにルーティングをしていきます。
お気に入りを登録するcreate
アクションは、本一覧から特定の本を選んで登録するので、resources books
の入れ子でルーティングをしています。その際アクション名をadd
に指定しています。
お気に入りを削除するdestroy
アクションは複数リソースのonly
オプションでルーティングしています。
- config/routes.rb
root "top#index" resource :sessions, only: [:new, :create, :destroy] resources :users #以下今回追加分 resources :books do member do #本一覧画面からお気に入り登録をする post "add", to: "favorites#create" end end #個人ページからお気に入りを削除する resources :favorites, only: [:destroy]
ビュー
本一覧画面にお気に入り登録のリンクを記述します。
- app/views/books/index.html.erb
<table> <thead> <tr> <th></th><th>タイトル</th><th>価格</th> </tr> </thead> <tbody> <% @books.each do |book| %> <tr> <!-- お気に入り登録ボタン ルートに従いパスを記述、POSTメソッドに指定 --> <td><%= link_to "登録", add_book_path(book), method: :post %></td> <!-- 本の詳細へのリンク --> <td><%= link_to book.name,book_path(book) %></td> <td><%= book.price %></td> </tr> <% end %> </tbody> </table>
ユーザの詳細画面を修正していきます。
削除リンクのパスfavorite_path
の引数を@favorite[i][:id]
にすることで、お気に入りレコードのIDが取得できるので、これでレコードを削除するパスが生成されます。(実は@favorite[i]
でもいけます)
- app/views/users/show.html.erb
<h3>お気に入りの本</h3> <table> <thead> <tr> <th>削除</th> <th>タイトル</th> <th>価格</th> </tr> </thead> <tbody> <!-- 削除リンクの為にindex付きのメソッドを使用 --> <% @user.books.each_with_index do |book, i| %> <tr> <td><%= link_to "削除",favorite_path(@favorites[i][:id]), method: :delete %></td> <td><%= book.name %></td> <td><%= book.price %></td> </tr> <% end %> </tbody> </table>
これでひとまずログインしたユーザが本をお気に入りを登録・削除できる機能が実装できました。
以上。