The cooperation between ActiveStorage and FormObject[Rails]

Tomoharu Tsutsumi
2 min readAug 3, 2019

I had an opportunity to use active storage and form object. While I was coding this, sometimes I was stuck. So, I’ll summarize this for myself of the future.

Situation

ruby 2.5.1 Rails 5.2.3

There are Investor model and User model. User model has_one Investor model, while Investor model belongs_to User model. There is a form to change status of investor and user. I wanted to enable the form to change status simultaneously. Investor model has these attributes: age, additional comment. User model has these attributes: email, last_name, first_name, phone_number.

Required definition

・The form can change status of investor and user simultaneously

・User must have profile image avatar

・If email status is changed, a confirmation email is sent to user. Of course, email status is not changed, the confirmation email is not sent.

How did I code

User model has already active storage, so the thing I must do is to enable the form to update avatar. Also, I thought form object is useful in order that the form can change two models. In addition, UserMailer has already been made.

I coded UserInvestorForm like below.

class UserInvestorForminclude ActiveModel::Modelinclude ActiveModel::Attributesattribute :user_id, :integerattribute :email, :stringattribute :last_name, :stringattribute :first_name, :stringattribute :phone_number, :stringattribute :age, :integerattribute :additional_comment, :stringattribute :avatardef update!  user = User.find(user_id)  if user.email != email && user.update(email: email,                                      last_name: last_name,                                      first_name: first_name,                                      phone_number: phone_number,    user.avatar.attach(avatar)    investor_update(user)      UserMailer.confirmation_change_mail_instructions(user).deliver_later    return :updated_with_email  elsif user.update(last_name: last_name, 
first_name: first_name,
phone_number: phone_number)
user.avatar.attach(avatar) investor_update(user) return :updated_without_email else return :false endenddef investor_update(user)user.investor.update!(age: age, additional_comment: additional_comment)endend

Update method has three patterns. If the status which includes email, confirmation mail is sent. However, if the status change doesn’t have email, confirmation mail is not sent. Also, when the status change fails, nothing happens. There is user_id attribute, this is sent from controller like below.

UserInvestorForm.new(user_params.merge(user_id: current_user.id))

Also, I must pay attention to avatar’s class. I used string for this attribute at first. However, this doesn’t work. In this case, we should not specify the class.

Moreover, I used return in if condition. Why? In controller, I must have change redirect when user and investor status has been changed. Redirect_to can’t be used in Model. So, I used this. The content of controller is like below.

case user_investor_form.update!when :update_with_email  redirect_to user_settings_path, flash: { success: t(".success") }when :updated_without_email  redirect_to investor_settings_path, flash: { success: t(".success") }when :false  flash[:danger] = t(".failure")  render :showend

If you think this article good, please follow me!

I update articles once a week!

https://twitter.com/tomoharutsutsum

--

--

Tomoharu Tsutsumi
Tomoharu Tsutsumi

Written by Tomoharu Tsutsumi

5+ years Full Stack SWE (Ruby, Go, TypeScript, JavaScript) | Former Founding Engineer of AI Startup in Canada

No responses yet