Skip to main content

refactoring polymorphic actions

General • Asked by Sean M

Hi Chris! I implemented the notification system based on your video with the partials. Works perfectly. I've got some problem though when user wanna check out the notification. When he/she clicks on the notification (either in dropdown or notification page) the following things must happen:

  • the checked_at attr gets set to current time (same for all types of notification)
  • the unchecked notification number gets decreased by 1 (same for all types of notification)
  • user gets redirected where the notification action happened (different for all types of notification)

At the moment I link every type of notification action (commented, accepted, etc.) to the custom checking_decreasing action route where first checked_at gets set and unchecked notification number gets decreased. Then based on the notification.notifiable_type and notification.action I redirect them to the desired page. So if sby commented on product then by clicking the notification you will get on that page. But as you see below there are so many combinations for redirecting that things got pretty messy in no time.

What kinda refactoring approach would you take here? I was thinking about creating a NotificationRedirectionsController where every notification_action + notifiable_type combination would have a separate action like def product_commented or def team_invitation_accepted etc. Is that a good idea? Do you know any refactoring technique for this case?

_commented.html.erb (same link in _commented.json.jbuilder

<%= link_to checking_decreasing_user_notifications_path(current_user, 
                                                        notifiable_type: notification.notifiable_type, 
                                                        notifiable_id: notification.notifiable_id, 
                                                        notification_action: notification.action
                                                        ) do %>

notifications controller / custom action

def checking_decreasing
  current_user.decreasing_comment_notification_number(params[:notifiable_type], 
                                                      params[:notifiable_id]
                                                      )
  redirect_to notification_redirection_path(params[:notifiable_type],
                                            params[:notifiable_id], 
                                            params[:notification_action]
                                            )
end

application controller

def notification_redirection_path(notifiable_type, notifiable_id, action)
  if action == "commented"
    if notifiable_type == "ProductCustomer"
      product_customer = ProductCustomer.find(notifiable_id)
      product_id = product_customer.product_id
    elsif notifiable_type == "ProductLead"
      product_lead = ProductLead.find(notifiable_id)
      product_id = product_lead.product_id
    end
    route = case notifiable_type
            when "Post"
              posts_path(anchor: "post_#{notifiable_id}")#{}"/posts#post_#{notifiable_id}"
            when "Product"
              product_path(notifiable_id, anchor: "comment-panel")#/products/#{notifiable_id}#comment-panel"
            when "ProductLead"
              product_product_lead_path(product_id, notifiable_id, anchor: "comment-panel")#{}"/products/#{product_id}/#{notifiable_type}/#{notifiable_id}#comment-panel"
            when "ProductCustomer"
              product_product_customer_path(product_id, notifiable_id, anchor: "comment-panel") #/products/#{product_id}/#{notifiable_type}/#{notifiable_id}#comment-panel"
            end
  elsif action == "invited"
    if notifiable_type == "Product"
      product_path(notifiable_id, anchor: "product-invitation-well")
    elsif notifiable_type == "ProductCustomer"
      product_customer = ProductCustomer.find(notifiable_id)
      product_id = product_customer.product_id
      product_product_customer_path(product_id, notifiable_id)
    end
  elsif action == "accepted"
    if notifiable_type == "Product" #team member invitation
      product_product_owner_panels_path(notifiable_id)
    elsif notifiable_type == "ProductCustomer" #referencer invitation
      product_customer = ProductCustomer.find(notifiable_id)
      product_id = product_customer.product_id
      product_product_owner_panels_path(product_id)
    end
  end
end

Login or Create An Account to join the conversation.

Subscribe to the newsletter

Join 27,623+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.