この期間の CHANGELOG.md
へのコミットは3件。
ActionPack, ActiveModel, ActiveStorageに関してそれぞれ1件。
ActionPack
ActionDispatch::Request
クラスのインスタンス変数 @remote_ip
を更新できない不具合を修正した
コミット: Updated `ActionDispatch::Request.remote_ip=` · rails/rails@bf14a8e
修正は remote_ip=
メソッドの @remote_ip = nil
の一行だけ。
def remote_ip @remote_ip ||= (get_header("action_dispatch.remote_ip") || ip).to_s end def remote_ip=(remote_ip) @remote_ip = nil set_header "action_dispatch.remote_ip", remote_ip end
引用: rails/request.rb at bf14a8e23526447b9893ed66090f898da68eb7f1 · rails/rails
@remote_ip = nil
をせずに remote_ip
メソッドを呼んでいたため、set済みの @remote_ip
のまま書き変わらない不具合があった。
ActiveModel
freeze
された ActiveModel
のオブジェクトに対して attribute
の書き変えをできないようにした
コミット: Raise FrozenError for frozen objects when trying to write to a · rails/rails@54b1574
概要はCHANGELOG.mdにある例の通り。
class Animal include ActiveModel::Attributes attribute :age end animal = Animal.new animal.freeze animal.age = 25 # => FrozenError, "can't modify a frozen Animal"
引用: rails/CHANGELOG.md at 54b157442171d28c7e9553537aef7a6ae571aad7 · rails/rails
修正は ActiveModel:: Attributes::ClassMethods
モジュールの define_method_attribute=
メソッド。
def define_method_attribute=(name) ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method( generated_attribute_methods, name, writer: true, ) do |temp_method_name, attr_name_expr| generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{temp_method_name}(value) raise FrozenError, "can't modify frozen #{self.class.name}" if frozen? name = #{attr_name_expr} write_attribute(name, value) end RUBY end end
なるほどこういう実装になっていたのか〜。
ActiveStorage
ActiveStorage::Blob#url
でパーマネントリンクを作れるようになった
コミット: Permanent URLs for public storage blobs · rails/rails@feab703
config/storage.yml
に新しいキー public: true | false
を設定することで、 true
の場合はパーマネントリンクを作ることができる。未設定の場合は false
で、今まで通り期限付きのリンクになる。
ActiveStorage::Blob#url
を見てみる。ここでは service.url
(ActiveStorage::Service#url
) を呼んでる。
def url(expires_in: ActiveStorage.service_urls_expire_in, disposition: :inline, filename: nil, **options) filename = ActiveStorage::Filename.wrap(filename || self.filename) service.url key, expires_in: expires_in, filename: filename, content_type: content_type_for_service_url, disposition: forced_disposition_for_service_url || disposition, **options end
引用: rails/blob.rb at feab7031b57040afa2b2f5f78f9251dbad6cbdf8 · rails/rails
ActiveStorage::Service#url
を見てみる。if public?
で public_url
or private_url
に振り分けてる。
def url(key, **options) instrument :url, key: key do |payload| generated_url = if public? public_url(key, **options) else private_url(key, **options) end payload[:url] = generated_url generated_url end end
引用: rails/service.rb at feab7031b57040afa2b2f5f78f9251dbad6cbdf8 · rails/rails
ActiveStorage::Service
クラスの public_url
と private_url
は未実装(raise NotImplementedError
)となっており、このクラスを継承している各ストレージサービスのクラスで public_url
と private_url
を実装している。具体的な実装は各クラスを参照。
ActiveStorage::Service::AzureStorageService
ActiveStorage::Service::DiskService
ActiveStorage::Service::GCSService
ActiveStorage::Service::S3Service
子クラスで実装を分けたい(かつ未実装だったらエラー吐きたい)ときに、親クラスで raise NotImplementedError
にしとくの便利。よくある(定石的な)実装なのかな。これまでまともにOSSのコードリーディングしてなかった&設計関連の本もほぼ読んでないからこの辺の設計論?みたいなもの、自論として確立できてないんだよなぁ。ともかく勉強になった。