Rails upgrade notes
⇑ Email
Last update
2025-03-07
2025-03-07
«rails notable/interesting changes from v4 to edge»
TODO
Rails 8
1 2 3 4 5 6 7 | # importmap + dartsass, NO hotwire rails new myapp-sass \ --asset-pipeline=propshaft --css=sass \ --skip-action-mailbox --skip-action-text \ --skip-hotwire --skip-jbuilder --skip-test --skip-system-test \ --skip-bootsnap --skip-brakeman --skip-ci --skip-dev-gems \ --devcontainer |
- Rails.error.unexpected: report the given error when in production, or raise it when in development (for conditions not supposed to happen)
- ActiveRecord: rollback a DB transaction with
raise ActiveRecord::Rollback - ActiveRecord: stop callbacks chain (eg. validation) with
throw :abort - YJIT enable by default (must be compiled in ruby)
- Controller.rate_limit
- .devcontainer folder when creating a new app.
- default erb PWA files (manifest, service-worker) in app/views/pwa
- GitHub CI files for Dependabot, Brakeman, RuboCop, and running tests by default (--skip-ci)
- Brakeman by default for static analysis of security vulnerabilities (--skip-brakeman option)
- ActiveRecord::Base.with_connection
- allow_browser
Rails 7
- AR generatestokenfor
- AM hassecurepassword
- AR normalizes
- AS MessagePack, api
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::Base.logger.silence{ ... }turns off logging in blockActiveRecord::Relation#pick=>.limit(1).pluck(*column_names).first- Model errors as objects @ Rails >= 6.1
- ActiveRecord
storewrapper aroundserializeto easily manage a hash value with attribute/keys methods accessors -- api, PR for dirty methods Model.optimizer_hintsPR andModel.annotatePR- 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_pathsindatabase.yml - eileen slides
connects_to,connected_toswitch 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
changesin 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:migratecreates development and test databases- migrations: sql expr as default value, es:
t.datetime :published_at, default: -> { 'NOW()' } - models derive from
ApplicationRecordinstead ofActiveRecord::Base - ActiveRecord
ORsupport, es:Post.where('id = 1').or(Post.where('id = 2')) - after commit shortcuts:
- ActiveRecord
Model.left_outer_joinssupport - 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 moreserializemisuse) - DB connection pool explained here -- sqlite has no pool
- Set database poolsize via
RAILS_MAX_THREADSenv ActiveRecord::Base.connection_pool.stat-- status info hash
- Set database poolsize via
find_in_batchesgot anend_atoptionactive_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
helpersproxy to use user defined helpers ActionController::Parameters#digcome per Hash#dig- ActionDispatch
Rails.application.reloader.wrap{}callback - Per-form CSRF tokens --
config.per_form_csrf_tokens_enabled = false/true protect_from_forgerydoen't run first anymore, it is simply queued as the other callbacks, use optionprepend: trueto set it as the first callback- NB:
request_forgery_protectioninitializer removed from Rails--apibecause usually not needed
- NB:
- controller/model's strong parameters
- controller actions default to head :ok if no template exists
- helpers
div_forandcontent_tag_forwill be gone in Rails 5 => recordtaghelper gem - introduced the
#{partial_name}_iterationlocal 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_onanddiscard_oncatch 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::Rendererto render views, and usepumaas 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
ActionMailboxto process incoming emails -- guide- Action Mailer Preprocessing -- eg:
InvitationMailer.with(invitee: person).account_invitation.deliver_later, see also - email previews
- ActionMailer
rescue_fromcome 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_ssldeprecatesActionController#force_ssl - new default headers
X-Download-Options: noopenandX-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.enctakes precedence overconfig/credentials.yml.enc, userails credentials:edit --environment stagingto 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_taghelper: 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_chainin favor ofModule#prepend-- howto
- rails API mode: hp
rake xxx:yyytasks proxied byrails xxx:yyy- config
serve_static_filesmoved topublic_file_server.enabled
⇑ Development
rails console --sandboxdon'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
dotcommand, runRails.application.routes.router.visualizerand 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 notescustom tags -- PRrails notestask -- shows search code for FIXME/OPTIMIZE/TODO- 📺 Rails 5 video tour by DHH on youtube
rails newadds 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 ... TAGal poso di<<-TAG...TAGrimuove 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
