简体   繁体   中英

Rails Partials - conditionality with locals

I have the following code in a Rails partial being used in some mailers but am not happy with my solution and have the feeling this is far from optimal.

I have an email which

From my mailer:

def the_email_i_am_sending(user, inquiry, params = {})
  get_variables(inquiry) #This also provides access to my `@user` object
  @contact_name = [params[:guest_last_name].to_s, " ", params[:guest_first_name].to_s].join

I always have @user but on occasion a specific partner will call our API with additional params of [:guest_last_name] and [:guest_first_name] as defined above. This allows me to define @contact_name as a separate instance variable.

When this is .present? ie not nil, I want to render @contact_name in a field on the email rather than the @user.login that would pull from our DB.


My mailer view then uses the following code to decide which partial it will render.

<% if @contact_name.present? %>
  <%= render 'meet_your_guest_v3', tujia_guest: @contact_name %>
<% else %>
  <%= render 'meet_your_guest_v3' %>
<% end %>

My solution is then to utilise this code in the partial being rendered in the mailer. It seems a little verbose but I am unsure about the correct usage of local_assigns.has_key?

<% if local_assigns.has_key?(:partner_guest) %>
  <%= partner_guest %> <p>(via our partner</p>
<% else %>
  <%= @user.login %>
<% end %>

Is there a better way?

You should definitely follow the advice from @Jon regarding dealing with params in your controller/mailer. Additionally you should just pass @contact_name every time to the underlying partial, regardless if it is present or not, then check only where you want to render it, if it is present. This way you would skip one conditional:

#email_view.html.erb
render 'meet_your_guest_v3', parnter_guest: @contact_name

_contact_name.html.erb
<% partner_guest.present? %>
...

A further step could be using a special decorator object, which would deal with the presentation logick. It would check wether contact_name was provided from outside or from the model and render the desired html tag for the contact_name (or it could just return it as string). See following pseudocode using the draper gem:

class MyController < ApplicationController
  def send_mail
    @user = User.find(...).decorate(
      contact_name: [params[:guest_last_name].to_s, " ", params[:guest_first_name].to_s].join
    )
   MyMailer.the_email_i_am_sending(@user)
  end
end


class MyMailer < ApplicationMailer
  def the_email_i_am_sending(user)
    @user = user
    mail(to: ..., subject: ...)
  end
end


class UserDecorator < Draper::Decorator
  def contact_name_tag
    if (contact_name.present?)
      h.content_tag(:div, contact_name)
    else
      h.content_tag(:div, user_name)
    end
  end
end

#email_view.html.erb
<%= @user.contact_name_tag %> 

However if the presentation logic isn't very complicated, going with a couple conditionals and perhaps extracting them into basic rails helpers is fine and using a presenter may be an overkill

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM