ActionMailer単体で、HTMLメール送るコードをとにかくすぐ書きたいんです。。

なんというナマケモノでしょう。。

HTMLメールのサンプルを探してぐぐると大抵はもう.html.erbを作っています。
それがもう面倒臭い場合あるいはとにかくHTMLメール送信を試したい場合はこんな調子です。

require 'action_mailer'
require 'yaml'
require 'erb'

conf = YAML.load_file('config.yml')
ActionMailer::Base.smtp_settings = {
  address: 'smtp.gmail.com',
  port: 587,
  domain: 'smtp.gmail.com',
  authentication: :plain,
  user_name: conf['mailer']['user_name'],
  password: conf['mailer']['password'],
  enable_starttls_auto: true
}
ActionMailer::Base.raise_delivery_errors = true
ActionMailer::Base.delivery_method = :smtp

class Mailer < ActionMailer::Base
  default from: 'aaaaaaaaa@bbbbbb.com'

  def html_mail(to, subject, body)
    mail(to: to, subject: subject) do |format|
      format.html { render text: body }
    end
  end
end

Mailer.html_mail('xxxxx@yyyyyyy.com','html mail test', '<b>bold?<b><br /><i>italic?</i>').deliver

一杯書きましたがformat.textformat.htmlに変えるだけです。。

参考

Rubyでメールを送る - Qiita [キータ]

ActiveRecordでselectしたはずのデータにアクセスできないんです

超はまった。。

priceカラムを持つitemsテーブルがあるとして、商品の日々の価格を記録しているとします。
今日の価格が前日比でどうなったか知るべく、こんな調子のものを書いたとして

q = Item.find_by_sql(<<-SQL)
  select
    t1.price - t2.price as price_change
  from
    items t1
      inner join items t2
        on t1.id = t2.id
        and t2.register_date = 昨日
  where
    t1.register_date = 今日
SQL

puts q.first.price_change #=> nil

なんでや。。なんでnilなんや。。

そう、priceというカラムが既に存在するので、select句に書いた列別名price_changeに対しておそらくActiveRecordのattribute_changeが先に利いているものと思われます。
上の例でputs q.first.attributesするとちゃんとprice_changeが存在するので、おそらくそっちのせいでしょう。
列別名を別にしてあげればうまく差額を返してくれます。私はfluctuationに変えましたよ。。

今回はSELECT文の列別名のネーミングがActiveRecordの作法に合わなかっただけですが、既存のテーブルが似たような有様の場合は要注意ですね。
わざわざ列別名を用意してあげるとか、その列だけattributes[attr]って調子でアクセスするとか。scopeをうまく使えば何も気にしなくても良くなるのかな?

ActionMailerとERBを単体で使ってRailsみたいにメールを飛ばしたいんです

もうrails使えよみたいな。。

require 'yaml'
require 'action_mailer'
require 'erb'

conf = YAML.load_file('config.yml')
ActionMailer::Base.smtp_settings = {
  address: 'smtp.gmail.com',
  port: 587,
  domain: 'smtp.gmail.com',
  authentication: :plain,
  user_name: conf['mailer']['user_name'],
  password: conf['mailer']['password'],
  enable_starttls_auto: true
}
ActionMailer::Base.raise_delivery_errors = true
ActionMailer::Base.delivery_method = :smtp

class Mailer < ActionMailer::Base
  default from: aaaaaaaa@bbbbbbb.com

  def notice(to, subject, body)
    mail(to: to, subject: subject) do |format|
      format.text { render text: body }
    end
  end
end

Mailer.notice('xxxxxx@yyyyy.com', 'subject', ERB.new(DATA.read, nil, '-').result(binding)).deliver
__END__
本日 <%= Time.now.strftime('%F') %> の買い物リスト

<%- ['きのこの山', 'GTA5'].each do |item| -%>
・<%= item %>
<%- end -%>

前回のActionMailer使用例のuser/passをyamlから取ってくるように変えました。
yamlは単体で使うとシンボルでアクセスできないんですね。。

railsで.html.erbを書く時、<%- -%>と書けばその行の行頭空白・行末改行をトリムしてくれましたが、erbを単体で書く場合はERB.newの引数でtrim_modeに'-'を明示しなければいけません。

またActionMailerでメールを投げるメソッド名にはルールというか予約名があるかもしれません。ちゃんと調べていませんが、上記のMailer.noticeは最初Mailer.sendという名前にしていまして、このとき引数toに渡したメールアドレス文字列をなぜかメソッド名として解釈されてしまい何度もmethod missingエラーをもらいました。

D:/RailsInstaller/Ruby1.9.2/lib/ruby/gems/1.9.1/gems/actionmailer-3.1.0/lib/action_mailer/base.rb:455:in `method_missing': undefined method `xxxxx@yyyyyyy.com' for Mailer:Class (NoMethodError)

こんな調子のエラーです。メソッド名をsendddとかにしたらエラーが出なくなったので、メソッド名が悪いのかと。
2013/10/13訂正 これは単にObject#sendを呼んでしまっているんでしょうね。。オーバーライドできていないのは私が基本的なことをわかっていないからでしょう。うう。。

参考

ActionMailer単体でメールを送信したいんです

SMTPサーバはGmailで。。

require 'action_mailer'

ActionMailer::Base.smtp_settings = {
  address: 'smtp.gmail.com',
  port: 587,
  domain: 'smtp.gmail.com',
  authentication: :plain,
  user_name: '俺のメール',
  password: '俺のパスワード',
  enable_starttls_auto: true
}

ActionMailer::Base.raise_delivery_errors = true
ActionMailer::Base.delivery_method = :smtp

class HelloMailer < ActionMailer::Base
  default :from => 'hogehoge@sample.com'

  def createMessage(to, subject, body)
    mail(:to => to,
         :subject => subject) do |format|
      format.text { render :text => body }
    end
  end
end

HelloMailer.createMessage('宛先@gmail.com', 'hello', 'こんにちは、世界!').deliver
# => Net::SMTPAuthenticationError: 534-5.7.9 Application-specific password required. Learn more at

なんでや。。Application-specific password?
そうだった、Googleアカウントは2段階認証にしてたんだった。
Googleのアプリケーション固有パスワードを作成してsmtp_settingsに設定したらうまく送信できた。

参考

実はそもそもSMTPとかPOPとかよく知らない状態だったので。。

sqlite3初心者のテキトーなメモ

ヘルプ

sqlite3 -helpか、sqlite3実行後に.help

DBファイルを作る

PS$sqlite3 .\practice.db
SQLite version 3.7.3
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .databases
seq  name             file
---  ---------------  ----------------------------------------------------------
0    main             C:\hoge\piyo\fuga\practice.db
sqlite>

.databasesってやると0バイトのこのファイルが生成される。何もせずに.exitだと何も作られない。

テーブル作ってなんかやる

sqlite> create table prac (date_time text);
sqlite> .tables
prac
sqlite> begin;
sqlite> insert into prac values('日付 ' || strftime('%Y-%m-%d %H:%M:%S', datetime('now', 'localtime')));
sqlite> select * from prac;
日付 2013-10-06 16:08:42
sqlite> 

begin;しないとトランザクションが始まらない。
begin;して何か操作するとprac.db-journalというのが作られて、commit; rollback; end;するとなくなる。
endするとcommitされる。
commit/rollbackするとendしなくてもトランザクションが終わる。sqlplusのつもりでやってはいけない。

データをファイル出力する

select文の結果が見づらいのでね。

sqlite> .output test.txt
sqlite> select * from prac;
sqlite> 

単にSQL実行結果の出力先を標準出力からファイルに向けただけ。
標準出力に戻すには

sqlite> .output stdout
sqlite> select * from prac;
日付 2013-10-06 16:08:42
sqlite> 

select文の結果を見やすくする

はじめからこれが出来ていればいいんですよ。。

sqlite> .header on
sqlite> .mode column
sqlite> .width 30
sqlite> select * from prac;
date_time
------------------------------
日付 2013-10-06 16:08:42

カラム幅をいちいち指定しないとデフォルトでぶつ切り表示されてしまうのが困りもの。

sqlite3起動パラメータでも指定可能。

PS$sqlite3.exe -header -column .\practice.db
SQLite version 3.7.3
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> select * from prac;
date_time
----------
日付 2013-

カラム幅は指定できません。。

外部ファイルに記述したSQLを実行する

sqlite> .read aiueo.txt
date_time
------------------------------
日付 2013-10-06 16:08:42

alterが貧弱ゥ

alter table hoge add column piyo;

でカラムを追加するか

alter table hoge rename to piyo;

でテーブル名を変更するしかできない。

カラム名を変更したい場合は地道な作業が必要。
って、え。。railsのsqlite3アダプタってマイグレーションカラム名変える時本当にそんなことやってんの。。

参考

などなど。

キーボードを掃除したいんです

クッキーばばあの相手をずっとしてました。。
ただいま秒間14億個のクッキーを焼かせていただいております。。Click Frenzyもっとこい。。

キーボードを掃除しました。
参考:キーボードの掃除の仕方について
こちらを参考にしまして。

キートップを洗ったあと渇くのに一晩待つのいやだったし、ドライヤーじゃなかなか渇かなかったので、バスタオルに包み縛って、枕カバーに入れてチャックして、それで乾燥機に放り込みました。洗濯ネットに入れただけだと乾燥機の中でカラカラうるさすぎて近所迷惑になったので。
数分で渇きました。バスタオルや枕カバーも水分吸ってくれたし。

まあそれにしてもキートップ外した後が汚かったのなんのって。埃と抜け毛がすごかったですが、干からびた米もあったし、なにやら小虫の死骸らしきものまで。。

という感じですごくキモかったのでキーボードカバーを買おうとしたら、どうもちゃんとサイズの合うものが全然見つからず……
汚くなるたびに洗うの面倒なので、今度キーボードが汚くなったらカバーとセットで買い換えようかと。リアフォ買ってみようかな。

rubyでcaseを使ってもうちょっといい感じに書けないものかな?

と思っていたら。。

Rubyのcaseを〇〇(言語名)のswitch文だと思っている人たちにぼくから一言ガツンと申し上げたい

つまりこんな書き方が出来る。

obj = 'hoge piyo fuga'
other_obj = {}

val = begin
  case obj
  when nil then 'nilでした'
  when other_obj then '他といっしょ'
  when ->p{p.is_a?(Hash)} then 'Hashです'
  when ->p{p.is_a?(String) && p.split(' ').include?('hoge')} then 'hoge'
  else 'parse error'
  end
end

p val #=> "hoge"

すごいですね-。