Rails upgrade notes
⇑ Email
Last update
2023-09-21
2023-09-21
«rails notable/interesting changes from v4 to edge»
TODO
- https://www.toptal.com/ruby-on-rails/rails-6-features
- https://bogdanvlviv.com/posts/ruby/rails/what-is-new-in-rails-6_0.html
- https://medium.com/rubyinside/whats-coming-to-rails-6-0-8ec79eea66da
- https://prograils.com/posts/new-features-rails-6-multiple-databases-parallel-tests-action-mailbox-etc
- https://matthewhoelter.com/2018/09/18/deploying-ruby-on-rails-for-ubuntu-1804.html
- https://github.com/wg/wrk
- learn WebSocket using ActionCable
- -----
- cleanup fish/fisher
- install: rvm + function, nvm + function, node, yarn
- rails new rails6test
- -----
- testing howto
- news in JS?
- multi threading notes
News { ActiveRecord | ActionView | ActiveJob | ActionCable | Frontend | Email | ActiveStorage | Security | Core | Devel | Tools&Gems | Testing | Info }
Altro { Upgrade Exp. | References | Tools | Bench. | Books }
New in rails (till 2019-07-06)
⇑ ActiveRecord
ActiveRecord::Relation#pick
=>.limit(1).pluck(*column_names).first
- Model errors as objects @ Rails >= 6.1
- ActiveRecord
store
wrapper aroundserialize
to easily manage a hash value with attribute/keys methods accessors -- api, PR for dirty methods Model.optimizer_hints
PR andModel.annotate
PR- leaverage DB unique constraints:
- ActiveRecord's
reselect
,rewhere
,reorder
- ActiveRecord enum attribute (int value by name) -- api
Item.where(price: 10..)
-- endless ranges in where conditionsActiveRecord::Base.verbose_query_logs = true
: show the query source code line number- multi-db support: suggestions, rake tasks per db, replica option/ro db
- migrations path: PR1, PR2 -- define
migrations_paths
indatabase.yml
- eileen slides
connects_to
,connected_to
switch DB connection PR;connected_to?
check role and connectionrails db:schema:cache:dump
,rails db:schema:cache:clear
-- PR- fix query cache for multiple connections PR
Model.while_blocking_writes{}
blocks/deny DB writes
- migrations path: PR1, PR2 -- define
- Change SQLite 3 boolean serialization from t/f to use 1/0 => migrate old data in DB
Model#delegate_missing_to
-- PR- belongs_to new :default option -- es:
belongs_to :person, default: -> { Person.current }
- ActiveRecord
changes
in callbacks: PR and reference table find_each{|r| ... }
shortcut tofind_in_batches{|b| b.each{|r| ... } }
- also supports
limit
:Post.limit(10_000).find_each{|p| ... }
- also supports
- DB comments
db:migrate
creates development and test databases- migrations: sql expr as default value, es:
t.datetime :published_at, default: -> { 'NOW()' }
- models derive from
ApplicationRecord
instead ofActiveRecord::Base
- ActiveRecord
OR
support, es:Post.where('id = 1').or(Post.where('id = 2'))
- after commit shortcuts:
- ActiveRecord
Model.left_outer_joins
support - foreign keys now supported in create_table DSL
- Active Record ignored_columns -- no accessor methods and no show in queries
- multi context validations -- es:
record.valid?(:ctx_name)
People.in_batches(of: 100){|rel| rel.where... }
-- vedi ActiveRecord::Relation#in_batches- ActiveRecord.suppress -- silently disable record save in block (es:
Model.suppress{...}
) - Attributes API: define attr with a
Proc
, see commit (no moreserialize
misuse) - DB connection pool explained here -- sqlite has no pool
- Set database poolsize via
RAILS_MAX_THREADS
env ActiveRecord::Base.connection_pool.stat
-- status info hash
- Set database poolsize via
find_in_batches
got anend_at
optionactive_record.warn_on_records_fetched_greater_than
-- info
⇑ ActionView
- ActionText: rich text editor integrated with ActiveRecord and ActiveStorage (images/attachments)!! -- guide, intro
- ActionView helper
current_page?
form_with
=form_for
+form_tag
: article, PR1, PR2- new tag helpers -- es:
tag.div(...)
- better controller's
helpers
proxy to use user defined helpers ActionController::Parameters#dig
come per Hash#dig- ActionDispatch
Rails.application.reloader.wrap{}
callback - Per-form CSRF tokens --
config.per_form_csrf_tokens_enabled = false/true
protect_from_forgery
doen't run first anymore, it is simply queued as the other callbacks, use optionprepend: true
to set it as the first callback- NB:
request_forgery_protection
initializer removed from Rails--api
because usually not needed
- NB:
- controller/model's strong parameters
- controller actions default to head :ok if no template exists
- helpers
div_for
andcontent_tag_for
will be gone in Rails 5 => recordtaghelper gem - introduced the
#{partial_name}_iteration
local variable in partials rendered with a collection - live streaming for persistent connections
- caching/faster rendering:
- template dependencies with wildcard support
- strong ETag --
Response#strong_etag=, weak_etag=, fresh_when, stale?
- views cache control -- es:
fresh_when
- declarative etags
⇑ ActiveJob / background jobs
- ActiveJob -- interface for existing queuing systems
- vedi anche: ActionMailer#deliver_later, GlobalID
retry_job
,retry_on
anddiscard_on
catch multiple exceptions- ActiveJob priority support
config.active_job.queue_adapter = :async
-- run jobs in threads a la sucker_punchqueue_name_prefix
-- PR
⇑ ActionCable / websockets
- ActionCable channel_prefix in your cable.yml
- ActionCable -- websockets: live features, chat, notifications | via redis or postgres
- see
ActionController::Renderer
to render views, and usepuma
as a separate process in production
- see
⇑ Frontend
- webpack integration: PR1, PR2 (make default), hp
- yarn javascript package manager used by default -- PR1, PR2, folders
- removed jQuery; vanilla UJS -- guide, jquery-rails, jquery-ujs
- turbolinks:
- turbolinks 5 and 📺 railsconf video
- moved to a separate repo
data-turbolinks-track="true"
moved todata-turbolinks-track="reload"
- Sprockets gzip files
- Sprockets 4 upgrade -- source maps, manifest.js, ES6 support
ActionMailbox
to process incoming emails -- guide- Action Mailer Preprocessing -- eg:
InvitationMailer.with(invitee: person).account_invitation.deliver_later
, see also - email previews
- ActionMailer
rescue_from
come nel controller
⇑ ActiveStorage / upload to cloud -- guide
- ActiveStorage/ActiveJob Mirror direct uploads
- include blob via
Model.with_attached_columnname
-- avoids N+1 query - video/pdf preview
- custom previewers
config.active_storage.routes_prefix = '/files'
custom route prefix
⇑ Security & Paranoia
- MessageEncryptor -- enc/dec strings
- logger/inspect's per model attributes filter -- es:
Model.filter_attributes = [:iban, :cf]
config.action_dispatch.use_cookies_with_metadata = true
-- Add Purpose/Name Metadata to Cookies to enhance security- ActiveRecord.
has_secure_password
: you can specify the attribute name - app-wide
config.force_ssl
deprecatesActionController#force_ssl
- new default headers
X-Download-Options: noopen
andX-Permitted-Cross-Domain-Policies: none
- Content-Security-Policy header DSL, moz ref -- disabled by default in 5.2
- credentials storage PR, guide --
rails credentials:edit
- multi env support:
config/credentials/production.yml.enc
takes precedence overconfig/credentials.yml.enc
, userails credentials:edit --environment staging
to edit specific file secrets PR, guide -- eg:rails secrets:edit
,rails secrets:show
- multi env support:
- secure cookies server side enforced expire time -- es:
cookies.signed[:user_name] = { value: "bob", expires: 2.hours }
- SSL exclude option:
config.ssl_options = { redirect: { exclude: -> request { request.path !~ /healthcheck/ } } }
- Active Support's way to write to a file atomically (thread safe) with
File.atomic_write
⇑ Core/config changes
- new Zeitwerk library loader: blog post, HP
- HTTP early hints/preloading
preload_link_tag
helper: preload + http2 early hints- HTTP2 early hints, PR
- bootsnap installed by default -- TODO: crontab for periodic clean of tmp/cache
- routes: Custom url helpers and polymorphic mapping
- monkey patching is the past:
- use ruby refinements instead of monkey patching
- Deprecate
alias_method_chain
in favor ofModule#prepend
-- howto
- rails API mode: hp
rake xxx:yyy
tasks proxied byrails xxx:yyy
- config
serve_static_files
moved topublic_file_server.enabled
⇑ Development
rails console --sandbox
don't write changes to DB -- PR+cfg- byebug > 8.2.1 is faster
- faster dev reload: set in Gemfile
group :development{gem 'listen', '~> 3.0.4'}
⇑ Tools / External gems
- Router Visualizer: PR, sample -- install graphviz
dot
command, runRails.application.routes.router.visualizer
and save the string to an html file - ActiveRecord XML serialization moved in a gem
- Rails-observers -- separa le callbacks dai models/controllers
- ActiveResource -- consume json via rest
⇑ Testing
- Capybara Integration with Rails (AKA System Tests) -- with selenium and chrome, guide, parallel tests
⇑ Info / Minor changes / Good to know
Array#extract!
-- removes and returns the elements for which the block returns a true value (come select ma modifica la variabile)- execjs: mini_racer replaces therubyracer
rails notes
custom tags -- PRrails notes
task -- shows search code for FIXME/OPTIMIZE/TODO- 📺 Rails 5 video tour by DHH on youtube
rails new
adds a defaultconfig/puma.rb
- String#parameterize per creare id ai titoli dei blog posts
- Array#inquiry.any?(:xxx) -- finds symbols and strings matching xxx
- locale yaml files auto-reloaded in development
- date and time:
DateTime.now.prev_occurring(:monday)
-- PR- Date/Time
#on_weekend?
and#on_weekday?
:D - Time vs DateTime -- commit
- Enumerable#pluck
⇑ Upgrade experiences -- google search
⇑ References
- what's new: https://medium.com/rubyinside/whats-coming-to-rails-6-0-8ec79eea66da
- https://bogdanvlviv.com/posts/ruby/rails/what-is-new-in-rails-6_0.html
- -------------
- https://weblog.rubyonrails.org
- https://guides.rubyonrails.org/upgrading_ruby_on_rails.html
- https://edgeguides.rubyonrails.org/6_0_release_notes.html
- https://guides.rubyonrails.org/5_2_release_notes.html
- https://guides.rubyonrails.org/5_1_release_notes.html
- https://guides.rubyonrails.org/5_0_release_notes.html
- https://guides.rubyonrails.org/4_2_release_notes.html
- https://guides.rubyonrails.org
⇑ Tools
- scaling ruby apps
- 📺 DHH youtube videos on writing sw well
- MiniMagick
- ruby's set: a collection of unordered values with no duplicates
obj.method(:method_name).source_location
=> mostra dov'e' definito il metodo<<~TAG ... TAG
al poso di<<-TAG...TAG
rimuove gli spazi di indentazione!- thor -- build powerful command-line interfaces
⇑ Benchmark howto
1 2 3 4 5 6 7 8 9 | require 'benchmark' a = [:a, :b] b = :b n = 10000000 Benchmark.bm do |x| x.report { n.times do !(Array(a) & Array(b)).empty? end } x.report { n.times do Array(a).include?(b) end } end |
1 2 3 4 5 6 7 8 | require 'benchmark/ips' # instructions per second require 'uri' uri = 'http://example.com/foos_json?foo=heyo' Benchmark.ips do |x| x.report('URI.parse') { URI.parse(uri) } end |
vedi esempi di barnchmark in Hash#deep_merge PR
⇑ Books
- rails6 (beta)
- rails5 test