<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hassan Ahmed</title>
    <description>The latest articles on DEV Community by Hassan Ahmed (@hassanahmed).</description>
    <link>https://dev.to/hassanahmed</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1250780%2F0a49c3a5-6c01-4431-9c43-73a8bde1c773.jpeg</url>
      <title>DEV Community: Hassan Ahmed</title>
      <link>https://dev.to/hassanahmed</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hassanahmed"/>
    <language>en</language>
    <item>
      <title>Rails 7.1 Framework Defaults 🚧</title>
      <dc:creator>Hassan Ahmed</dc:creator>
      <pubDate>Sun, 09 Nov 2025 19:37:29 +0000</pubDate>
      <link>https://dev.to/hassanahmed/rails-71-framework-defaults-l2f</link>
      <guid>https://dev.to/hassanahmed/rails-71-framework-defaults-l2f</guid>
      <description>&lt;p&gt;I am already a bit late with this post but like one of my previous posts about enabling &lt;a href="https://dev.to/hassanahmed/enabling-rails-70s-new-framework-defaults-hkb"&gt;Rails 7 defaults&lt;/a&gt;, documenting the same procedure for &lt;code&gt;7_1&lt;/code&gt; has been something on my todo list.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚧
&lt;/h2&gt;

&lt;p&gt;Since with &lt;code&gt;7_1&lt;/code&gt; we have quite a few new framework defaults we need to go through and enable and since I want to keep all the information in one single post, I will be updating this blog post incrementally with information about more defaults periodically (weekly is the plan at least).&lt;/p&gt;

&lt;h2&gt;
  
  
  Disclaimer:
&lt;/h2&gt;

&lt;p&gt;Before starting, I'd like to give a disclaimer, any change you make to your production application should always go through some pre prod screening/testing. I have tried to present some resources and information around the impact of these defaults, but there might be something I may have missed. If you find something, please do leave a comment so I can also update and learn. Thanks in advance for that and reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rails.application.config.action_dispatch.default_headers
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;br&gt;
The comment that comes with the new framework default files when upgrading to 7_1 also is self explanatory but to summarize again, enabling this would remove &lt;code&gt;X-Download-Options&lt;/code&gt; default header which mostly serves only IE (seems like IE8 only). IE8 has not been supported for quite some time now as well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reference(s):&lt;/strong&gt; &lt;br&gt;
&lt;a href="https://www.invicti.com/white-papers/whitepaper-http-security-headers/#XDownloadOptionsHTTPHeader" rel="noopener noreferrer"&gt;For further reading&lt;/a&gt; &lt;/p&gt;
&lt;h2&gt;
  
  
  Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality = false
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Previous value:&lt;/strong&gt; &lt;code&gt;nil&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;New value:&lt;/strong&gt; &lt;code&gt;false&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Purpose:&lt;/strong&gt;&lt;br&gt;
To understand the impact of enabling this particular flag I had to go through some PRs on rails official repo and came across the following &lt;a href="https://github.com/rails/rails/pull/44826" rel="noopener noreferrer"&gt;PR&lt;/a&gt;. The description of which provides an important hint towards a bug that exists with the deprecated behavior of comparing &lt;code&gt;AC::Parameters&lt;/code&gt; with a &lt;code&gt;Hash&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Reads of the key with fetch (also delete, values_at) lead to all subsequent read operations of the key to return an array of raw Hashes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The pull request further refers to another one (&lt;a href="https://github.com/rails/rails/pull/44812/files#diff-99dab0dfb4d0cfa044997480d5aa1b100dc60347a10cedd6d8f7a0395f6a6efdR279" rel="noopener noreferrer"&gt;#44812&lt;/a&gt;) which previously added deprecation warning around this behavior. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tips&lt;/strong&gt;&lt;br&gt;
To detect any negative side effects of untoggling this one can rely on CI pipeline and of course, deploying it to some pre prod environment and monitor post prod roll out as well. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reference(s):&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/rails/rails/pull/44826" rel="noopener noreferrer"&gt;rails/rails #44826&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/rails/rails/pull/44812" rel="noopener noreferrer"&gt;rails/rails #44812&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Active Record Encryption now uses SHA-256 as its hash digest algorithm.
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;br&gt;
This one is also explained pretty well in the new framework defaults file. &lt;strong&gt;TLDR:&lt;/strong&gt; Based on your previous configuration set the appropriate value of AR encryption to either &lt;code&gt;SHA1&lt;/code&gt; or &lt;code&gt;SHA256&lt;/code&gt;. If you have no data encrypted via AR, use the latest configurations under 7_1.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reference(s)&lt;/strong&gt;&lt;br&gt;
This is pretty well explained in the comments &lt;a href="https://github.com/rails/rails/blob/7-1-stable/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_1.rb.tt#L41" rel="noopener noreferrer"&gt;right above&lt;/a&gt; this flag.&lt;/p&gt;
&lt;h2&gt;
  
  
  Rails.application.config.active_record.run_commit_callbacks_on_first_saved_instances_in_transaction
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;br&gt;
The &lt;a href="https://github.com/rails/rails/pull/45280" rel="noopener noreferrer"&gt;PR&lt;/a&gt; introducing this change itself explains it really well along with an example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLDR&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt; within a transaction updating multiple instances referencing to the same record in db would only fire &lt;code&gt;after_commit&lt;/code&gt; upon first update.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt; trigger the callback when internal state of the record within the transaction is likely to match the database value&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reference(s)&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/rails/rails/pull/45280" rel="noopener noreferrer"&gt;PR introducing the change&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Rails.application.config.active_record.sqlite3_adapter_strict_strings_by_default = true
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;br&gt;
First of all this is not relevant if you are not using SQLite.&lt;br&gt;
It seems historically SQLite accepted double quoted strings as identifiers like column names and single quoted strings as string literals. Later double quoted strings were also permitted to be accepted as literal strings if they didn't match an identifier (a column name for example). So to avoid this confusion or running into unexpected issues you can uncomment this flag, which will impose a stricter convention by default i.e. single quotes = literal string, double quotes = identifiers&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reference(s)&lt;/strong&gt;&lt;br&gt;
Explained &lt;a href="https://www.sqlite.org/quirks.html#double_quoted_string_literals_are_accepted" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Rails.application.config.active_record.allow_deprecated_singular_associations_name = false
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Given you have a model structure like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Book &amp;lt; ApplicationRecord
  belongs_to :author
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You could do something like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Book.where(authors:....)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;authors&lt;/code&gt; is pluralized in the above query but when looking from the perspective of model and relationship, a &lt;code&gt;book&lt;/code&gt; can have a single &lt;code&gt;author&lt;/code&gt;. There is more to this change, it comes with an underlying performance improvement as well. More details can be found on the provided references below. Uncommenting this flag, would now raise an error if you refer to a singular association in pluralized manner in your queries. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tips&lt;/strong&gt;&lt;br&gt;
Once uncommented, if you have good test coverage, it will point out most of the areas where this change needs to be made, I'd do some manual scanning of codebase as well and of course some testing before merging this change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;References(s)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/rails/rails/pull/45452" rel="noopener noreferrer"&gt;rails/rails PR#45452&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Rails.application.config.active_job.use_big_decimal_serializer = true
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;br&gt;
Background job adapters often store the payload of a job like its name and arguments supplied to it after serializing it to &lt;code&gt;JSON&lt;/code&gt;. This comes with a small inconsistency that during this process of serializing to &lt;code&gt;JSON&lt;/code&gt;, &lt;code&gt;BigDecimal&lt;/code&gt; type of data is serialized to &lt;code&gt;String&lt;/code&gt;. This can lead to unintended behavior or bugs when the said background job expecting &lt;code&gt;BigDecimal&lt;/code&gt; ends up with &lt;code&gt;String&lt;/code&gt; values.&lt;/p&gt;

&lt;p&gt;Uncommenting this flag ensures, the &lt;code&gt;BigDecimal&lt;/code&gt; values are serialized and fetched as their original datatype. &lt;/p&gt;

&lt;p&gt;⚠️ As advised in the &lt;code&gt;new_framework_defaults_7_1.rb.tt&lt;/code&gt; file, you need to make sure, your application and all possible replicas which will be effected by this change have been successfully upgraded to &lt;code&gt;Rails 7_1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tips&lt;/strong&gt;&lt;br&gt;
Along with CI to report any inconsistencies or errors, I'd also take a look on what arguments the background jobs within the project expect to be extra sure before flipping this flag.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/rails/rails/pull/45618" rel="noopener noreferrer"&gt;#45618&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Rails.application.config.active_support.raise_on_invalid_cache_expiration_time = true
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;br&gt;
Uncommenting this flag will raise an error if a cache expiration time of past was provided when caching some data. PR linked in references introducing this change (#45842) gives a very good idea of what to expect with this change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/rails/rails/pull/45842" rel="noopener noreferrer"&gt;#45842&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Follow up PR &lt;a href="https://github.com/rails/rails/pull/45892" rel="noopener noreferrer"&gt;#45892&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Rails.application.config.active_record.query_log_tags_format = :sqlcommenter
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;br&gt;
This default can be given two values &lt;code&gt;:legacy&lt;/code&gt;(existing behaviour) or &lt;code&gt;:sqlcommenter&lt;/code&gt;. Providing it the latter, will add additional context to the SQL queries generated from &lt;code&gt;ActiveRecord&lt;/code&gt; which can be used for better observability and monitoring sources that trigger slow SQL queries.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;will also try and some examples of the new vs old versions of logs&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://open-telemetry.github.io/opentelemetry-sqlcommenter/" rel="noopener noreferrer"&gt;Read more about SQLCommenter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rails/rails/pull/45081" rel="noopener noreferrer"&gt;#45081&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rails/rails/issues/45139" rel="noopener noreferrer"&gt;Issue with proposal&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Rails.application.config.active_support.message_serializer = :json_allow_marshal
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;br&gt;
Prior to 7_1, Rails used &lt;code&gt;:marshal&lt;/code&gt; as serializer when using &lt;a href="https://api.rubyonrails.org/v5.2.3/classes/ActiveSupport/MessageEncryptor.html" rel="noopener noreferrer"&gt;MessageEncryptor&lt;/a&gt; or &lt;a href="https://api.rubyonrails.org/classes/ActiveSupport/MessageVerifier.html" rel="noopener noreferrer"&gt;MessageVerifier&lt;/a&gt;, which (as mentioned) is vulnerable to deserialization attacks. The proposed new value &lt;code&gt;:json_allow_marshal&lt;/code&gt; instead uses &lt;code&gt;:json&lt;/code&gt; serializer going forward but also can deserialize content previously serialized using &lt;code&gt;:marshal&lt;/code&gt; (backwards compatible).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;&lt;br&gt;
As pointed out in &lt;a href="https://github.com/rails/rails/pull/48170" rel="noopener noreferrer"&gt;#48170&lt;/a&gt;, going forward it will be changed to &lt;code&gt;json&lt;/code&gt; only serializer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://guides.rubyonrails.org/v7.1/configuring.html#config-active-support-message-serializer" rel="noopener noreferrer"&gt;Rails Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rails/rails/pull/48170" rel="noopener noreferrer"&gt;#48170&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Rails.application.config.active_support.use_message_serializer_for_metadata = true
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;br&gt;
This change introduces an optimization in how messages are serialized, as mentioned in the attached PR rather than twice, messages are " URL-encoded only once".&lt;/p&gt;

&lt;p&gt;As mentioned in the actual &lt;code&gt;new_framework_defaults_7_1.rb&lt;/code&gt;, messages serialized in the old format can still be read after enabling this default, however, once enabled, message serialzed with this new format won't be readable if the flag is disabled again.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;&lt;br&gt;
Its also further recommended, if you are in process of bumping from 7 to version 7_1, first deploy the version update to your infrastructure with this flag disabled and then perform a subsequent deployment with this flag enabled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/rails/rails/pull/46848" rel="noopener noreferrer"&gt;#46848&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Rails.application.config.log_file_size
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;br&gt;
Pretty self explanatory, for &lt;code&gt;test&lt;/code&gt; and &lt;code&gt;development&lt;/code&gt; environment it sets a maximum size for the logfile to be 100 mb.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/rails/rails/pull/44888" rel="noopener noreferrer"&gt;#44888&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Rails.application.config.active_record.raise_on_assign_to_attr_readonly = true
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;br&gt;
Once enabled, any attempt to assign any value to an attribute declared as &lt;a href="https://api.rubyonrails.org/classes/ActiveRecord/ReadonlyAttributes/ClassMethods.html#method-i-attr_readonly" rel="noopener noreferrer"&gt;readonly&lt;/a&gt; in the model will raise an error.&lt;/p&gt;

&lt;p&gt;There are a few ways to also verify this does not results in new errors being thrown like&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if there are no declaration of such attributes you are safe&lt;/li&gt;
&lt;li&gt;if there are such attributes, if possible it would be worth checking if they are being updated&lt;/li&gt;
&lt;li&gt;test coverage if done properly should also be able to point any regression in CI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/rails/rails/pull/46105" rel="noopener noreferrer"&gt;#46105&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To be continued....&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Rails 7.1: Changes to $LOAD_PATH</title>
      <dc:creator>Hassan Ahmed</dc:creator>
      <pubDate>Sun, 09 Mar 2025 13:34:03 +0000</pubDate>
      <link>https://dev.to/hassanahmed/rails-71-changes-to-loadpath-549p</link>
      <guid>https://dev.to/hassanahmed/rails-71-changes-to-loadpath-549p</guid>
      <description>&lt;p&gt;Having worked in Ruby on Rails, you must know we don't need to manually require files that reside inside the &lt;code&gt;app&lt;/code&gt; folder. The framework internally takes care of loading and reloading files in the app folder and apart from it, if we want to &lt;code&gt;autoload&lt;/code&gt; any other folder e.g. &lt;code&gt;lib&lt;/code&gt;, that can be achieved by pushing it to the collection &lt;code&gt;config.autoload_paths&lt;/code&gt; (more details can be found in the &lt;a href="https://guides.rubyonrails.org/v7.0/autoloading_and_reloading_constants.html" rel="noopener noreferrer"&gt;guides&lt;/a&gt;). Historically, all autoload paths were pushed to &lt;code&gt;$LOAD_PATH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLDR:&lt;/strong&gt; &lt;code&gt;$LOAD_PATH&lt;/code&gt; a.k.a &lt;code&gt;$:&lt;/code&gt; is a collection of absolute paths that you can &lt;code&gt;require&lt;/code&gt; (this &lt;a href="https://www.youtube.com/watch?v=QIhfZRZdFXU" rel="noopener noreferrer"&gt;video&lt;/a&gt; although a bit old helped me in understanding this concept better)&lt;/p&gt;

&lt;p&gt;Starting &lt;code&gt;Rails 7_1&lt;/code&gt; autoloaded paths will no longer be added to &lt;code&gt;$LOAD_PATH&lt;/code&gt;. Since autoloaded files e.g. &lt;code&gt;app/models/user.rb&lt;/code&gt; are implicitly "required", it actually does makes sense to not bloat the &lt;code&gt;$LOAD_PATH&lt;/code&gt; and it only contains list of paths that we need to require and are not handled by the autoloader. &lt;/p&gt;

&lt;p&gt;If you are upgrading from a previous version of Rails this option was part of the new Rails 7_1 defaults under the flag&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rails.application.config.add_autoload_paths_to_load_path = false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Uncommenting this default will also no longer move the autoloaded paths to &lt;code&gt;$LOAD_PATH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Upgrading from a previous version&lt;/strong&gt;&lt;br&gt;
In terms of impact, if you just upgraded from a previous version of Rails, I assume for the most part it should be safe as autoloaded files should not be required in the first place and test coverage should point out if this can be a breaking change. Moreover, I'd test this first on a non prod environment by playing around the application a bit and later when shipped to prod, keep an eye on any errors that pop up.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;References:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/rails/rails/blob/main/guides/source/upgrading_ruby_on_rails.md#autoloaded-paths-are-no-longer-in-load_path" rel="noopener noreferrer"&gt;Rails 7_1 upgrade guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=QIhfZRZdFXU" rel="noopener noreferrer"&gt;Loading code with Ruby&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>defaults</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Enabling Rails 7.0's New Framework Defaults</title>
      <dc:creator>Hassan Ahmed</dc:creator>
      <pubDate>Sat, 18 May 2024 23:48:06 +0000</pubDate>
      <link>https://dev.to/hassanahmed/enabling-rails-70s-new-framework-defaults-hkb</link>
      <guid>https://dev.to/hassanahmed/enabling-rails-70s-new-framework-defaults-hkb</guid>
      <description>&lt;p&gt;Recently I had a chance to enable Rails 7's new framework defaults, I thought I'd share the research and reasoning that I was able to extract for each of these via blog post. &lt;/p&gt;

&lt;h3&gt;
  
  
  Before you proceed:
&lt;/h3&gt;

&lt;p&gt;This is not the complete list of the new Rails 7 defaults, there are a few missing, that I will try and document soon in this same blog. &lt;/p&gt;

&lt;p&gt;Also I'd recommend, doing your own research along the way and suggest any improvements/corrections to this post as well. &lt;/p&gt;

&lt;p&gt;Lets jump right into the new defaults then! &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;Rails.application.config.action_view.button_to_generates_button_tag = true&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Uncommenting this default would now generate a &lt;code&gt;button&lt;/code&gt; tag rather than an &lt;code&gt;input&lt;/code&gt; tag of type submit in the from rendered by the &lt;code&gt;button_to&lt;/code&gt; helper.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To Uncomment&lt;/strong&gt;&lt;br&gt;
This should be safe to uncomment if you are not using &lt;code&gt;button_to&lt;/code&gt; helper. If you are, ideally test coverage should be in place to detect any unexpected behavior or you can also manually test if its feasible. There may be some slight change in behavior e.g if you are relying on some param being sent to the controller by the &lt;code&gt;button_to&lt;/code&gt; helper prior to uncommenting this line.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;code&gt;Rails.application.config.action_view.apply_stylesheet_media_default = false&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Uncommenting this line would mean the stylesheet html tags that are rendered by &lt;code&gt;stylesheet_link_tag&lt;/code&gt; will no longer include the &lt;code&gt;media&lt;/code&gt; attribute set to &lt;code&gt;screen&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To Uncomment&lt;/strong&gt;&lt;br&gt;
Uncommenting this line would mean, style sheets will be applied to all media types unless you have explicitly specified &lt;code&gt;media&lt;/code&gt; attribute on any. For safety you can check all the included stylesheets in your project and determine if you need to make any changes and then uncomment this line.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;code&gt;Rails.application.config.active_support.hash_digest_class = OpenSSL::Digest::SHA256&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;You may notice in the &lt;code&gt;new_framework_defaults_7_0.rb&lt;/code&gt; file mentioning the impact of this change, which is cache invalidation.&lt;br&gt;
In order to gather some more information I looked at the &lt;a href="https://github.com/rails/rails/blob/main/activesupport/lib/active_support/digest.rb"&gt;ActiveSupport::Digest&lt;/a&gt; which basically has just 3 class methods, a setter &amp;amp; getter for &lt;code&gt;hash_digest_class&lt;/code&gt; and the &lt;code&gt;hexdigest&lt;/code&gt; method. Furthermore, I searched across the &lt;code&gt;rails/rails&lt;/code&gt; repo to find the usage of &lt;code&gt;ActiveSupport#hex_digest_class&lt;/code&gt; (if interested this &lt;a href="https://github.com/search?q=repo%3Arails%2Frails%20hexdigest&amp;amp;type=code"&gt;link&lt;/a&gt; leads to the search results) to find most of its usage only around code that deals with caching. This included caching of views, &lt;code&gt;active_record&lt;/code&gt; queries, http ETAGs and also cache keys for the cache store you have set e.g. redis, filestore etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To Uncomment:&lt;/strong&gt;&lt;br&gt;
Uncommenting this would mean cache keys will now be read/generated using the new SHA::256 digest and existing cache keys will no longer be readable resulting in cache misses across all the impacted areas and resulting in new cache keys being generated using the new digest. This can mean a dip in performance initially for your application. Also, previously generated cache entries using SHA::1 will stay in the cache store you have configured until their expiration which may also mean some additional storage being consumed from your cache store for that time period.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;code&gt;Rails.application.config.active_support.remove_deprecated_time_with_zone_name = true&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;With this flag commented, &lt;code&gt;ActiveSupport::TimeWithZone.name&lt;/code&gt; returned &lt;code&gt;Time&lt;/code&gt; rather than the actual class name. Uncommenting this flag will return the actual class name rather than this overridden implementation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To Uncomment&lt;/strong&gt;&lt;br&gt;
If you are not using &lt;code&gt;ActiveSupport::TimeWithZone.name&lt;/code&gt; anywhere in your codebase, this should be safe to uncomment. If you are, you may have to handle those cases accordingly or disable this default in the &lt;code&gt;application.rb&lt;/code&gt;, whatever works for your case. &lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;code&gt;Rails.application.config.active_support.cache_format_version = 7.0&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Rails 7 introduces a more optimized serialization format for caching. This new format should be able to read cache entries that were serialized with Rails 6.1 but, Rails 6.1 will not be able to read the entries serialized using this new format so only enable this flag after you don't plan to move back to using a previous Rails version.&lt;br&gt;
Refer to this &lt;a href="https://github.com/rails/rails/pull/42025"&gt;pull request&lt;/a&gt; if you are interested in knowing more details about the implementation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To Uncomment&lt;/strong&gt;&lt;br&gt;
As long as you have no plans to move back to Rails 6.1, you can safely enable this flag, as mentioned, cache entries serialized by 6.1 should be read by the new format as well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;&lt;br&gt;
It seems to enable this flag, you need to set it in &lt;code&gt;application.rb&lt;/code&gt; (&lt;a href="https://github.com/rails/rails/pull/45304"&gt;pull request&lt;/a&gt; for reference) as later an issue was raised highlighting that merely uncommenting this flag did not make the app use the newer cache format. You can verify yourself as well the behaviour in console by using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rails.cache.instance_variable_get(:@coder) 
# and check whether the returned value is ActiveSupport::Cache::Coders::Rails70Coder or ActiveSupport::Cache::Coders::Rails61Coder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;code&gt;Rails.application.config.active_support.executor_around_test_case = true&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Looking at this &lt;a href="https://github.com/rails/rails/pull/43734"&gt;PR&lt;/a&gt; to extract more details around this default, it looks like it should be relatively safe to uncomment it. This will allow data like &lt;a href="https://api.rubyonrails.org/classes/ActiveSupport/CurrentAttributes.html"&gt;Current Attributes&lt;/a&gt; to be reset after each request, even if there are multiple requests within a single test. (the &lt;a href="https://github.com/rails/rails/blob/main/railties/test/application/action_controller_test_case_integration_test.rb#L70"&gt;following&lt;/a&gt; test case also gives some idea). &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To Uncomment&lt;/strong&gt;&lt;br&gt;
If the build is green then it shouldn't be much of an issue in my opinion.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;Rails.application.config.active_support.isolation_level = :thread&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Quoting the comment next to this default&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you use a fiber based server or job processor, you should set it to &lt;code&gt;:fiber&lt;/code&gt;.&lt;br&gt;
Otherwise the default of &lt;code&gt;:thread&lt;/code&gt; if preferable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This description seems pretty clear in terms of what value should be set. In case you are using a thread based server like &lt;code&gt;puma&lt;/code&gt; and a thread based job processor like &lt;code&gt;Sidekiq&lt;/code&gt; you can uncomment this default.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;Rails.application.config.action_mailer.smtp_timeout = 5&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Sets the default timeout value for SMTP requests so that unfulfilled requests are timedout. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To Uncomment&lt;/strong&gt;&lt;br&gt;
I don't anticipate any regression coming out of uncommenting this default, the way I enabled this was to test some emails on a staging environments and all seemed to work and then closely monitor the bug tracking system of any timeouts.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;Rails.application.config.active_record.verify_foreign_keys_for_fixtures = true&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Quoting the changelog entry from &lt;a href="https://github.com/rails/rails/blob/7-0-stable/activerecord/CHANGELOG.md"&gt;rails 7 stable version&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tests will not run if there is a foreign key constraint violation in your fixture data.&lt;br&gt;
The feature is supported by SQLite and PostgreSQL, other adapters can also add support for it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;To Uncomment&lt;/strong&gt;&lt;br&gt;
If you are not using fixtures for your specs, this might have no impact at all for you. If you are, uncommenting this should raise the foreign key violations that you will have to fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;Rails.application.config.action_controller.raise_on_open_redirects = true&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;To prevent open redirect attacks, uncommenting this default will raise an error whenever &lt;code&gt;redirect_to&lt;/code&gt; or &lt;code&gt;redirect_back&lt;/code&gt; redirects to a different host. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To Uncomment&lt;/strong&gt;&lt;br&gt;
In my opinion having a good test coverage is important for this one, once uncommented (if there is proper test coverage), it should be able to highlight the areas from where external redirection is taking place. If its necessary to keep the redirection you can permit it by using &lt;a href="https://api.rubyonrails.org/v6.0.2.2/classes/ActionController/Redirecting.html"&gt;allow_other_host&lt;/a&gt; option in those places. You can also search your codebase for &lt;code&gt;redirect_to&lt;/code&gt; or &lt;code&gt;redirect_back&lt;/code&gt; to see whether at any of those places you are redirecting to an external host.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;Rails.application.config.action_controller.wrap_parameters_by_default = true&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Your Rails application may have an initializer by the name of &lt;code&gt;wrap_parameters.rb&lt;/code&gt; with similar &lt;a href="https://github.com/rails/rails/blob/6-0-stable/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt"&gt;content&lt;/a&gt;. The purpose of this functionality is to wrap parameters sent to a controller in a nested hash. For example and further reading please refer to &lt;a href="https://api.rubyonrails.org/v6.0.2.2/classes/ActionController/ParamsWrapper.html"&gt;this&lt;/a&gt; page from docs (v6).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To Uncomment&lt;/strong&gt;&lt;br&gt;
If you haven't made any changes to the &lt;code&gt;wrap_parameters&lt;/code&gt; initializer, this default is safe to uncomment, otherwise you can keep on using the customized version of your initializer and disable this default in &lt;code&gt;application.rb&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;Rails.application.config.active_support.use_rfc4122_namespaced_uuids = true&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Can safely be uncommented if you are not using any of the methods from &lt;a href="https://api.rubyonrails.org/classes/Digest/UUID.html"&gt;Digest::UUID&lt;/a&gt; in your codebase.&lt;/p&gt;

&lt;p&gt;From what I could gather after going through the changes in the mentioned PR (below), it fixes behavior of generating UUIDs when provided namespace is different from the ones defined in the class.&lt;/p&gt;

&lt;p&gt;Reference &lt;a href="https://github.com/rails/rails/pull/37682/files"&gt;PR&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;Rails.application.config.action_dispatch.default_headers&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This default changes the &lt;code&gt;X-XSS-Protection&lt;/code&gt; response header's value to &lt;code&gt;0&lt;/code&gt; which means disabling it in favor of CSP (Content Security Policy). It seems almost all major browser no longer support this header due to some of the vulnerabilities it came with.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/rails/rails/pull/41769"&gt;PR&lt;/a&gt; for more details.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To Uncomment&lt;/strong&gt;&lt;br&gt;
Its always good to have an effective CSP for your application, I'd recommend to create one if you haven't for your app before uncommenting this default.&lt;/p&gt;

&lt;p&gt;Thanks for reading, if you have some feedback or want to suggest some correction, please feel free to share those in the comments below. &lt;/p&gt;

&lt;p&gt;Programming bliss to you!!&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>howto</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Database Pool Management with Sidekiq and load_async</title>
      <dc:creator>Hassan Ahmed</dc:creator>
      <pubDate>Sun, 14 Apr 2024 22:04:57 +0000</pubDate>
      <link>https://dev.to/hassanahmed/database-pool-management-with-sidekiq-and-loadasync-41kh</link>
      <guid>https://dev.to/hassanahmed/database-pool-management-with-sidekiq-and-loadasync-41kh</guid>
      <description>&lt;p&gt;Recently I came across a very common issue after integrating a few Sidekiq jobs to a project. &lt;/p&gt;

&lt;p&gt;During this activity, I set the &lt;code&gt;pool&lt;/code&gt; size in &lt;code&gt;database.yml&lt;/code&gt; of the worker process equal to the concurrency I set for Sidekiq. Its recommended to have &lt;code&gt;pool&lt;/code&gt; size equal to or greater than the concurrency setting otherwise, you can run into issues or even if there are no apparent errors, this will likely cause additional latency in the queues.&lt;/p&gt;

&lt;p&gt;But strangely, I still ran into this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ActiveRecord::ConnectionTimeoutError &amp;lt;background job name&amp;gt;

could not obtain a connection from the pool within 5.000 seconds (waited 5.062 seconds); all pooled connections were in use
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the error suggests, the worker thread executing the job attempted to obtain a database connection but was not able to and after waiting for 5 seconds raised this exception. &lt;/p&gt;

&lt;h2&gt;
  
  
  Possible Reason??
&lt;/h2&gt;

&lt;p&gt;In my case, the issue was not as straight forward as the &lt;code&gt;pool&lt;/code&gt; size being less than the total concurrency set for Sidekiq.&lt;/p&gt;

&lt;h3&gt;
  
  
  load_async
&lt;/h3&gt;

&lt;p&gt;I searched for the codebase for &lt;code&gt;Thread.new&lt;/code&gt; initially to see if there are any queries being executed in separate threads in any of the jobs, but the only occurrences I came across were not relevant.&lt;br&gt;
Secondly I looked for &lt;code&gt;load_async&lt;/code&gt; (which basically queries database asynchronously &lt;a href="https://www.rubydoc.info/github/rails/rails/ActiveRecord%2FRelation:load_async"&gt;details&lt;/a&gt;) and actually found it being used by one of the classes that was being instantiated and used in one of the background jobs. &lt;/p&gt;

&lt;p&gt;And that was it, despite having a &lt;code&gt;pool&lt;/code&gt; value equal to the concurrency that I have set in Sidekiq, having &lt;code&gt;load_async&lt;/code&gt; in one of the jobs meant, this was an additional (unaccounted) thread that can consume a connection from the &lt;code&gt;pool&lt;/code&gt; causing another thread to wait.&lt;/p&gt;

&lt;p&gt;With the root cause of the issue established, I adjusted my &lt;code&gt;pool&lt;/code&gt; size for the worker process (in &lt;code&gt;database.yml&lt;/code&gt;) as recommended &lt;a href="https://edgeguides.rubyonrails.org/configuring.html#config-active-record-global-executor-concurrency"&gt;here&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pool = total_concurrency + global_executor_concurrency + 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;code&gt;global_executor_concurrency&lt;/code&gt; refers to the number of asynchronous queries that can be executed concurrently and its default value is 4.&lt;/p&gt;

&lt;p&gt;Which meant for me, the eventual value of the &lt;code&gt;pool&lt;/code&gt; size I set was&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pool = total_concurrency + 4 + 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For me this was an interesting finding and hope it helps and save some time for you if you come across similar scenario.&lt;/p&gt;

&lt;p&gt;Happy Coding!&lt;/p&gt;

</description>
      <category>rails</category>
      <category>backenddevelopment</category>
      <category>sidekiq</category>
      <category>db</category>
    </item>
    <item>
      <title>Migrating attachments to ActiveStorage on the go.</title>
      <dc:creator>Hassan Ahmed</dc:creator>
      <pubDate>Sat, 27 Jan 2024 20:33:40 +0000</pubDate>
      <link>https://dev.to/hassanahmed/migrating-attachments-to-activestorage-on-the-go-3n8e</link>
      <guid>https://dev.to/hassanahmed/migrating-attachments-to-activestorage-on-the-go-3n8e</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;A little while back, the team I was part of was tasked with migrating attachments from &lt;code&gt;carrier_wave&lt;/code&gt; to &lt;code&gt;active_storage&lt;/code&gt;. Basically the original task was to migrate the storage location of the files for the project that was originally configured to use &lt;code&gt;carrier_wave&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This felt like a good opportunity to also migrate from using &lt;code&gt;carrier_wave&lt;/code&gt; to &lt;code&gt;active_storage&lt;/code&gt; since our application was already up to date with relatively recent rails version at the time and a solution provided out of the box from the framework makes more sense to use rather than relying on third party dependencies. Not to mention gems like &lt;code&gt;carrierwave&lt;/code&gt; and &lt;code&gt;paperclip&lt;/code&gt; have been the goto solution and rock solid for years before &lt;code&gt;active_storage&lt;/code&gt; was introduced.&lt;/p&gt;

&lt;h2&gt;
  
  
  Possible Solutions 💡
&lt;/h2&gt;

&lt;p&gt;Looking up online for similar case studies (migrate from &lt;code&gt;carrier_wave&lt;/code&gt;/&lt;code&gt;paperclip&lt;/code&gt; to &lt;code&gt;active_storage&lt;/code&gt;), I found a number of very helpful articles explaining in detail how to achieve this, a common approach I observed was to do the migration in one go via some dedicated rake task or db migration. In our case due to some constraints it wasn't feasible for us to have a single long running task to migrate all existing attachments. &lt;/p&gt;

&lt;p&gt;Considering these constraints we eventually decided to go with a different approach, perform the migration on the go. More precisely, migrate an attachment when its referenced from the codebase.&lt;/p&gt;

&lt;p&gt;The final flow of events that we came up with looked something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgalo1k9s99im7jatmtsw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgalo1k9s99im7jatmtsw.png" alt="flow chart" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For new uploads:&lt;/strong&gt;&lt;br&gt;
This case was simple enough, new uploads will be uploaded via &lt;code&gt;active_storage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For existing uploads&lt;/strong&gt;&lt;br&gt;
For existing uploads, we devised this sequence of events:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check if the requested attachment exists on &lt;code&gt;active_storage&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;if yes, return the attachment from &lt;code&gt;active_storage&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;if no, enqueue a job to attach the requested attachment to &lt;code&gt;active_storage&lt;/code&gt; and in the meantime return the &lt;code&gt;carrierwave&lt;/code&gt; attachment&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Implementation 💻
&lt;/h2&gt;

&lt;p&gt;Since I worked on this use case approximately a year ago, I will try and reconstruct the bits that I think are relevant and present those in the form of some pseudo implementation just to give an idea of the approach. I assume you will have active storage enabled already in your projects by this point.&lt;/p&gt;

&lt;p&gt;However, if you want to ask a question specific to your use case please share those in the comment, I will try my best to guide you.&lt;/p&gt;

&lt;p&gt;For the sake of this example lets take a simple use case where we have a &lt;code&gt;Profile&lt;/code&gt; model having an attachment by the name of &lt;code&gt;profile_picture&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The model will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Profile &amp;lt; ApplicationRecord
  mount_uploader :profile_picture, ProfilePictureUploader
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1. Enable ActiveStorage
&lt;/h3&gt;

&lt;p&gt;Firstly, we prepare our model to accept incoming attachments via &lt;code&gt;active_storage&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Profile &amp;lt; ApplicationRecord
  mount_uploader :profile_picture, ProfilePictureUploader
  has_one_attached :as_profile_picture # temporary alias used which will be removed later
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should allow us to enable attaching files to an instance of &lt;code&gt;profile&lt;/code&gt; via &lt;code&gt;as_profile_picture&lt;/code&gt; using &lt;code&gt;active_storage&lt;/code&gt;. The name &lt;code&gt;as_profile_picture&lt;/code&gt; is a temporary alias for now to avoid naming conflicts and will be later changed as a part of the clean up.&lt;/p&gt;

&lt;h4&gt;
  
  
  Note
&lt;/h4&gt;

&lt;p&gt;Something I'd do at this point is also to change any strong params or any code where a &lt;code&gt;profile_picture&lt;/code&gt; is assigned to an instance of &lt;code&gt;Profile&lt;/code&gt;. That should already allow us to take care of one part of the problem which is to upload new attachments to &lt;code&gt;active_storage&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Also create some sort of helper methods for example one good case to have a helper method would be to return the URL of the attachment for preview purposes based on the attachment type e.g. &lt;code&gt;is_a?(ActiveStorage::Attachment)&lt;/code&gt; or &lt;code&gt;is_a?(CarrierWave::Uploader)&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Handling existing attachments
&lt;/h4&gt;

&lt;p&gt;For existing attachments we'll attach them one at a time asynchronously to &lt;code&gt;active_storage&lt;/code&gt;. Having &lt;code&gt;carrier_wave&lt;/code&gt; uploader already mounted on the model we have access to the getter &lt;code&gt;profile_picture&lt;/code&gt; that we have already been using to access the respective attachment. We can override it slightly to also achieve the second objective which was to migrate existing attachment to &lt;code&gt;active_storage&lt;/code&gt;. Theoretically, that would mean doing something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Profile &amp;lt; ApplicationRecord
  mount_uploader :profile_picture, ProfilePictureUploader
  has_one_attached :as_profile_picture

  def profile_picture
    if as_profile_picture.attached?
      as_profile_picture
    else
      enqueue_attachment_migration("profile_picture")
      super
    end
  end

  private

  def enqueue_attachment_migration(attachment_name)
    MigrateAttachmentToActiveStorageJob.perform_async(id, class.name, attachment_name)
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As described in the diagram above with the latest changes we are able to now (for existing attachments):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check if they exist on &lt;code&gt;active_storage&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If yes, just return the attachment from &lt;code&gt;active_storage&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If no, return the attachment via &lt;code&gt;carrier_wave&lt;/code&gt; and enqueue a background job to attach the &lt;code&gt;profile_picture&lt;/code&gt; to the instance via &lt;code&gt;active_storage&lt;/code&gt; as well.&lt;/li&gt;
&lt;/ol&gt;

&lt;h5&gt;
  
  
  Background Job
&lt;/h5&gt;

&lt;p&gt;The background job essentially fetches the file currently attached via &lt;code&gt;carrier_wave&lt;/code&gt; and attaches it to the &lt;code&gt;as_profile_picture&lt;/code&gt; association.&lt;/p&gt;

&lt;p&gt;With these changes in place, this would take care of the second part of the use case we are trying to solve i.e. migrate existing attachments on the go asynchronously. &lt;/p&gt;

&lt;h2&gt;
  
  
  Post Migration Clean Up 🧹
&lt;/h2&gt;

&lt;p&gt;Once we are sure that all the attachments that were meant to be migrated have been successfully migrated we can perform some clean up and change the temporary alias we had declared in the model to track &lt;code&gt;active_storage&lt;/code&gt; attachments. &lt;/p&gt;

&lt;h3&gt;
  
  
  Database Clean Up
&lt;/h3&gt;

&lt;p&gt;Just a heads up before moving forward, I wasn't able to execute this part but will share some ideas about the clean up that can be done after all the attachments have been migrated.&lt;/p&gt;

&lt;p&gt;The names given to the attachments in the model, in our case &lt;code&gt;as_profile_picture&lt;/code&gt; are tracked in the &lt;code&gt;name&lt;/code&gt; column of the &lt;code&gt;active_storage_attachment&lt;/code&gt; table. We will need to write a script to update the column values from &lt;code&gt;as_profile_picture&lt;/code&gt; to &lt;code&gt;profile_picture&lt;/code&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Model Clean Up
&lt;/h3&gt;

&lt;p&gt;Once we have updated the &lt;code&gt;names&lt;/code&gt; in the &lt;code&gt;active_storage_attachments&lt;/code&gt; we can clean up some of the code we added earlier in the model to be something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Profile &amp;lt; ApplicationRecord
  has_one_attached :as_profile_picture
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if everything works we can even go and remove the &lt;code&gt;Uploader&lt;/code&gt; classes and &lt;code&gt;carrier_wave&lt;/code&gt; related attributes from the database schema.&lt;/p&gt;

&lt;h4&gt;
  
  
  Note
&lt;/h4&gt;

&lt;p&gt;At this point, I would also clean up/refactor the helper methods added accordingly e.g. removing any conditional behavior based on whether attachment was previously stored via &lt;code&gt;carrier_wave&lt;/code&gt; or &lt;code&gt;active_storage&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;To conclude I wanted to sum up what I thought was a newer perspective when it came to data migration, the idea behind writing this post was to present with an alternate idea for anyone looking for options. &lt;/p&gt;

&lt;p&gt;The code samples are just to give an idea, I initially felt working with a live project for this post but due to time constraint I wasn't able to. Also, I think &lt;code&gt;active_storage&lt;/code&gt; in terms of setup and configuration is well documented on a number of forums.&lt;/p&gt;

&lt;p&gt;Hope this was of some help for you, if you have questions or feedback feel free to share those in the comments.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>activestorage</category>
      <category>ruby</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
