Active Storage & Devise - Lets make it work
As a new software developer one of the great joys of life is discovering new gems that make your life easier. Bright eyed and bushy tailed I was when I heard of the newest one I could implement! Authentication — which frankly I found a little slow — would be faster. What joy! What bliss!
What my little brain couldn’t grasp was that this was a tool that was to be implemented with caution. Did I get my sessions working fast? Sure. Was I logging in and out with ease? You betcha’. HOWEVER, Devise is an incredibly powerful tool and to fully utilize its potential you have to understand what it is doing. Which I did not. So when it came to attempting to utilize Rails’ Active Storage feature or adding more fields to my forms I kept encountering the same problems.
I would take all the steps necessary but somehow it still would not save the file to my local device. The internet gave many tips and tricks for setting up Active Storage in a regular Rails App but nothing specific on using it with Devise. So I hope you enjoy this handy dandy hand book. From one developer to another. Don’t spend your whole day on this.
Step 1 — Gain access to your devise controllers and views.
Devise has its own built in view pages that it will be automatically asking redirecting to. In order to edit any of these you will need access to them. Run:
rails generate devise:views users
You will also need to be able to change what is happening in your Devise controllers. This stuff is all happening behind the scenes which is helpful — but as with everything it comes with less control over what you are doing. If you are a beginner developer just learning authentication you can easily spend your time trying to redirect something in your UsersController and thinking WHY IS THIS NOT WORKING. The truth is that all pre-made forms are going to respond first to any rules set upon them by the devise controllers. They have their own unless you change them. To access these make sure to run:
rails generate devise:controllers users
Step 2 — Regular Active Storage Setup
If you have been scouring the internet before this you have probably come across a lot of the same info for Active Storage Setup. It all pretty much goes like this :
Create your tables by running:
Next head over to your Model and declare your association with :
(In the example above I am calling the file I will be uploading image_file. You can name it whatever you please just be consistent throughout).
Head over to your form and include a field to upload it. As an example, let’s say I want a User to be able to upload a photo when they create their profile. I have already declared the association in my User model and now I head to “../app/views/devise/registrations/new.html.erb”. I add the following to my form:
<%= f.label :image_file %>
<%= f.file_field :image_file %>
Now the little tricky part…
Step 3 — Allowing Updates to Your Devise Params
In regular situations you would head over next to your user_controller.rb and add that little :image_file to your params but — Remember! Devise is utilizing its own controllers. So how can you override these? It is important to know that just like your regular controllers, Devise inherits from your Application Controller! Here is where we want to make sure new information is getting in.
Devise has something called the ParameterSanitizer specifically created for allowing specific values to each Devise scope. By default when using the parameter sanitizer it allows the following for its respective scopes —
sign in => password and remember me
sign up = > password and password confirmation
account_update = > password(new), password confirmation, and current_password
For more info on the ParameterSanitizer check out: https://www.rubydoc.info/github/plataformatec/devise/Devise/ParameterSanitizer
For our purposes we are going to write a method as defined in the RubyDocs and allow the new parameter of our image file.
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters
devise_parameter_sanitizer.permit(:signup, keys: [:image_file])
So what did we just do?
First we set a before_action to call on the configure_permitted_parameters IF what we are using is a devise_controller. Next we used .permit on the sanitizer to name the scope ( :sign_up for our purposes but this could also be :account_update, etc) and allow the image_file from before to pass through into the params. As a bonus — you can also use this to allow any other field to update properly into your table on the devise forms!
Step 4 — Make it viewable
Head over to the view page your form is directing to. In our case it is redirecting to our users’ show page. In the file proceed as usual for Active Storage files:
<% if current_user.image_file.attached? %>
<%= image_tag url_for(current_user.image_file) %>
<% end %>
Now, run that rails server, check it out, and pour yourself a drink. You earned it.