ruby-on-railsruby-on-rails-4acts-as-paranoid

How to make a helper method to check existance status of an object?


I'm using Rails4, And also using ActsAsParanoid to handle deleted dependencies in my views.

order.rb

class Order < ActiveRecord::Base
  ...
  has_many :ice_creams
  accepts_nested_attributes_for :ice_creams
  validates :user, :shift, :discount, :total, :total_after_discount, :paid, :remaining, presence: true
  ...
end

ice_cream.rb

class IceCream < ActiveRecord::Base
  ...
  belongs_to :sauce, with_deleted: true
  belongs_to :order
  validates :size, :basis, :flavors, :ice_cream_price, :extras_price, :total_price, presence: true
  ...
end

app/views/orders/show.html.erb

...
<ul>
  ...
  <li>Total:<%= @order.total %><li>
</ul>

<% @order.ice_creams.each do |ice_cream| %>
  ...
  <ul class=leaders>
    <li>Ice Craem Id:<%= ice_cream.id %></li>
    <li>Sauce:<%= ice_cream.sauce.present? ? ice_cream.sauce.name : "Deleted Value!" %></li>
  ...
<% end %>
...

If i deleted a sauce ActsAsParanoid soft deletes it and save my views from breaking. And the present? method helped me with permanently deleted sauces but As you may see sauces are optional in any ice_cream, So If any ice_cream doesn't have a sauce that will also display deleted value.

So I had to come up with more logic to determine if any ice_cream has no sauce, or had a deleted sauce. So i wrote this helper method.

application_helper.rb

def chk(obj, atr)
  if send("#{obj}.#{atr}_id") && send("#{obj}.#{atr}.present?")
    send("#{obj}.#{atr}.name")
  elsif send("#{obj}.#{atr}_id.present?") and send("#{obj}.#{atr}.blank?")
    "Deleted Value!"
  elsif send("#{obj}.#{atr}_id.nil?")
    "N/A"
  end
end

and then used...

app/views/orders/show.html.erb

...
<%= chk(ice_cream, sauce %>
...

But It returnd NoMethodError in Orders#show

undefined method `atr' for #< IceCream:0x007fcae3a6a1c0 >

My questions are...


Solution

  • Sorry I don't yet quite understand the whole situation so there might be a better solution but right now I can't propose it.

    What is wrong with your current code I think is how you call chk. It should be

    ...
    <%= chk(ice_cream, 'sauce') %>
    ...
    

    Notice that the second argument is a String instance (or it could a Symbol).

    And I think your chk method should be something like this

    def chk(obj, atr)
      attribute_id = obj.send("#{atr}_id")
      attribute = obj.send(atr)
    
      if attribute_id && attribute.present?
        attribute.name
      elsif attribute_id.present? and attribute.blank?
        "Deleted Value!"
      elsif attribute_id.nil?
        "N/A"
      end
    end
    

    I just refactored your method so it should be syntactically correct. But I haven't yet checked all those if logic.

    UPDATE

    Maybe it would be cleaner this way

    def chk(obj, attr)
      attr_id  = obj.send("#{attr}_id")
      attr_obj = obj.send(attr)
    
      if attr_id.present?
        attr_obj.present? ? attr_obj.name : 'Deleted Value!'
      else
        'N/A'
      end
    end