no_picture

PostGIS関連でRailsの本番環境でエラー

PostGIS 開発環境ではおきないのだけど、pointを作ろうとしてエラーが起きる。 NoMethodError (undefined method `point' for #<Proc:0x000000038dde90>) 見事に下記の通りだった。 https://github.com/rgeo/activerecord-postgis-adapter/issues/63 self.lonlat = Pin.rgeo_factory_for_column(:latlon).point(self.longitude, self.latitude) だったのを self.lonlat = Pin.rgeo_factory_for_column(:latlon, {}).point(self.longitude, self.latitude) に書き換え。rgeo_factory_for_columnの第2引数に {}を加えた。

no_picture

第2回 中国地方DB勉強会に参加したり、喋ったり。

第2回 中国地方DB勉強会 に参加しました。 O/R Mapping の話をするよ。特にActiveRecordの話をしたかった。 セッションしました。準備不足はいいわけにはできないけど、ぶっちゃけ準備不足で、対象者が詰め切れていませんでした。 とはいえ、スライドはアップロードしておきます。 O/R Mapping の話をするよ。ActiveRecord の話をしたかった。 from Tomohiko Himura よろしい、ならばMicro-ORMだ ORM の利点を長所もわかったんだけど、 ORM が使えない場面で ORM がもつ機能の一部を使いたい。そんなときに Micro-ORM が便利だよ。という話がつづきました。 特にデータのマッピングを操作する部分の機能を持っているようでした。 たしかに、普段のプログラミング生活では表現力の高いクエリビルダと値のマッピングができれば充分な感じは最近していたりもします。 スライド MySQL Cluster 解説 & MySQL Cluster 7.3 最新情報 MySQL と MySQL Cluster 異なる製品で、MySQLのストレージとして MySQL Clusterを利用したりできるようです。 単体でも使えるっぽいですが、よくわかっていません。 安価なマシンを並べて性能を出しつつ、高い可用性を実現します。 使われてる箇所としては、「艦コレ」で使われていたのが最近の話題っぽいです。 MySQLのストレージとして使えるので、InnoDBの互換性向上とかもやってるそうです。 スライド AWSで始めるPostgreSQL/MySQL AWS で MySQL や PostgreSQL をいれる話でした。 Wiki に内容がまとめられてます。 さくらインターネットにおけるデータベース提供の実際 特にレンタルサーバの話が印象的でした。 データベース不慣れな人が多く、そういった一部の人が共用サーバに不可をかけてしまったりするということは予想通り多いみたいです。 コントロールパネルが書籍との違いが出てしまうので、なかなかUIを変更できなっかたりもするそうです。 DBはIOがボトルネックになるので仮想化は向いてないのかなあ。なんて話もしてでていました。

no_picture

ActiveModelを利用してフォームを作成した時の型変換

対応するレコードがないフォームを使う場合、ActiveModelを使用することで、シンプルなビューを構築しつつ、処理はモデルにかけます。 しかし、ActiveModelのノウハウってあんまり落ちていません。 それなりに ActiveRecord に対する理解も必要で、難しいですね。 ハマったことなど共有していきたいと思います。 フォームからのデータは文字列ですが、ActiveRecord にはコラム自体には型があるため、型変換を自動的に行ってくれます。 これを無意識に使用していると ActiveModelではまります。 具体的には以下のテーブルがあったとします。 class CreateUsers < ActiveRecord::Migration def change create_table :users do |t| t.string :name t.integer :age t.boolean :is_person t.timestamps end end end 利用例を見てみましょう。 user = User.new(age: '20') user.age # => 20 user.age.class # => Fixnum user = User.new(is_person: "1") user.is_person # => true user.is_person.class # => TrueClass 文字列から作成しているけども、自動的に数値や、真偽値へと変換されています。 ActiveModel を使用する場合は以下のように実装しておくとよさそうです。 class User2 attr_reader :age, :is_person include ActiveRecord::ConnectionAdapters def initialize(attributes = {}) attributes.each do |key, value| send("#{key}=",value) end end def age=(age) @age = age.to_i end def is_person=(is_person) @is_person = Column.value_to_boolean(is_person) end end 代入する時に値を修正するのが インスタンス変数に直接アクセスした場合にも型が保証できて良いです。 「別に文字列でもいいよ。」なんてこともあると思いますが、 数値だとおもってうっかり使うと '20' * 3 -> '202020' となって欲しい 40とは大きく違います。 チェックボックスを利用すると "1" などなど、値として降ってきます。 特に 真偽値への変換ですが、とりあえずわからなかったので、自前でごまかしていたのですが、調べました。 ActiveRecord::ConnectionAdapters::Column にさままな型変換のメソッドが実装されています。 https://github.com/rails/rails/blob/v3.2.13/activerecord/lib/active_record/connection_adapters/column.rb その中の value_to_boolean を使用しました。 def value_to_boolean(value) if value.is_a?(String) && value.blank?

no_picture

ActiveRecord の has_many で生成されるメソッドってActiveRecord::Relationに変換できる配列なんですね。

タイトルのとおりなんですが、ArticleとComment とかあったりして、ちゃんと設定をしておくと article.comments とやると あるArticleに紐づいているCommentがとってこれる機能です。 まず、結論からいうと article.comments.to_sql とか article.comments.scoped とか article.comments.joinsとかできる!! ということです。 article.comments.create ってかける時点でうすうす思ってたんですが、これがわかっていると小回りがききます。返しているものが ActiveRecord::Relationのようなものです。classを確認すると Arrayって言われちゃいますが。 もうちょい深く 以下のクラスがあることを想定してみます。 class Article < ActiveRecord::Base has_many :comments end class Comment < ActiveRecord::Base belongs_to :artcile belongs_to :user end class User has_many :comment end さきほど紹介した技を紹介すると User.first かつ Article.first な Commentを探す場合、以下のように書けます a = Article.first u = User.first a.comments.merge(u.comments.scoped) すると、こんな SQLができます。 SELECT "comments".* FROM "comments" WHERE "comments"."article_id" = 1 AND "comments"."user_id" = 1 aとかuとかを引数な関数を用意するとウハウハな気がしてこないでしょうか。 joinだってできます。 a =

no_picture

read_attributeの存在を知らなかった、死にたい - rails

Railsの ActiveRecordで レコードの属性にアクセスする際は動的に生成されたメソッドを使いますが、そのようなメソッドを上書きしている場合、値に直接アクセスする必要があります。このような属性情報は @attributes に保存されています。 /lib/active_record/attribute_methods.rbに定義されてる attributes メソッドを経由してアクセスしていましたが、なんとなく @attributes へ直接アクセスするだけかとおもってたのですが、違ったようです。 def attributes attrs = {} attribute_names.each { |name| attrs[name] = read_attribute(name) } attrs end という定義になってました。 attribute_names は文字列で属性の一覧を返すので @attributesは 普通のHashでキーが文字列です。 もし email というの属性にアクセスしたい場合は attributes["email"] になります。 attributes[:email] ではアクセスすることができません。 しかし、 read_attributeは シンボルでも文字列でも使用することができて、 read_attribute :email でも read_attribute "email" のどちらでも良いみたいです。 ちなみにエイリアスがあって [] メソッドになります。なので self[:email] などでアクセスできます。pubilcメソッドです。 read_attribute があるということはも write_attribute もあります。 ついでにもう少し深追い read_attributeの実装もついでにおってみると def read_attribute(attr_name) self.class.type_cast_attribute(attr_name, @attributes, @attributes_cache) end となってました。クラスメソッドを経由するようです こいつも中身を追うと def type_cast_attribute(attr_name, attributes, cache = {}) #:nodoc: return unless attr_name attr_name = attr_name.to_s if generated_external_attribute_methods.method_defined?(attr_name) if attributes.has_key?(attr_name) || attr_name == 'id' generated_external_attribute_methods.send(attr_name, attributes[attr_name], attributes, cache, attr_name) end elsif !attribute_methods_generated?

no_picture

ActiveRecordで今のスコープをそのまま返したい

あるオプションパラメータがあるかどうかで、条件が変わるような処理を書いてると、オプションがない場合、ActiveRecord::Relationが欲しくなるような場面があります。 例えば @articles = Article @articles = @articles.where(valid: true) if params[:valid] みたいな感じになっちゃって@articles = Articleって何?な状態になります。 メソッド化しようとするとさらに困るのですが、scopedを使うと以下のように書けるようです。 @articels = Article.scoped @articles = @articles.where(valid: true) if params[:valid] なんか異臭がしなくなりましたね。 だから、どうした?って思う方もいるかもしれませんがメソッド化すると、 def self.valid(is_valid = nil) scoped.where(valid: true) if is_valid scoped end となります。scopedなしで書かこうとするとちょっと困ります。 そんだけ。