The cooperation between ActiveStorage and FormObject[Rails]
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