0
votes

I have a User model that can have many Websites. For example, I will be able to call User.websites and it will pull up an ActiveRecord array of all of the websites that the User owns. But each website uses Single Table Inheritance (STI) and a type column that will determine the type of the website, like commercial, advertising, or forum. My problem is, that I was to make a case/when statement that runs a function if the the User has a website that is of a certain type. for example:

@user = User.first
case @user.websites
    when includes?(Commercial)
        'This user has a commercial website'
    when includes?(Forum)
        'This user has a forum website'
    when include?(Ad)
        'This user has a advertisement website'
end

Does anyone have a clue on the best way to do such a thing?

3
calling relation on a model rather than on instance object @user makes no sense at allJoe Half Face
@JoeHalfFace I guess that was misleading, I will not be calling the modal itself. Just an instance of it. It was more of an example placeholder. I'll edit that. Thankssclem72
@engineersmnky Does it really matter what the functions do? Lets say that all the functions do is output a string. I'll make an edit.sclem72
what do you expect, if user has more, that 1 type of a website in user.websites?Andrey Deineko
@sclem72 practically yes it does matter and what if a user has a Commercial website and a Forum website? Either way the user itself should not concern itself with such logic as it pertains to the website not the user. It's not just about writing code but making it easily maintainable in the future. This way you can define an appropriate interface for implementing any kind of website in the future without the need to make changes to models that should not be impacted.engineersmnky

3 Answers

4
votes

Shortest way to do this is using a the map method. Just one line!

   @user.websites.select(:type).uniq.map{
       |x| puts "This user has a #{x.type.downcase} website" 
   }

Or if you want to have these strings in an array.

@user.websites.select(:type).uniq.map{|x| x.type.downcase}

If you want to run functions. I would advice naming the functions in a friendly way such as commercial_cost, forum_cost, etc.. so that you can use the send method which makes your code compact.

@user.websites.select(:type).uniq.map{ |x| @user.send(x.type.downcase + "_cost") }
2
votes
def types
  'This user has following websites: ' +  
     websites.pluck(:type).map(&:downcase).join(', ')
end
0
votes
#user.rb

def return_data(*types)
  types.each do |t|
    if Website.where(:user_id => self.id, :type=> t).length>0
      send "method_for_owners_of_#{t}_site"
    end
  end
end

def method_for_owners_of_Commercial_site
end
#...

 @user.return_data(["Commercial"])
 @user.return_data(["Commercial", "Ad"])
 ...

According to Rails API

When you do Firm.create(name: "37signals"), this record will be saved in the companies table with type = “Firm”.