Reputation: 7883
I'm fairly new to Ruby, and I have a code organisation problem.
I have a class, called Movie, which includes a module called IMDBMovieInfo
.
class Movie
include IMDBMovieInfo
attr_accessor :name
attr_accessor :year
attr_accessor :movieID
end
IMDBMovieInfo
has a method which takes the movieID and uses it to build an IMDB URL:
module IMDBMovieInfo
def imdb_url()
"http://www.imdb.com/title/tt#{self.movieID}/"
end
end
The problem here is I'm not sure I should be referencing something in the movie class, as IMDBMovieInfo
doesn't know about that class, and shouldn't. I could add an argument of a movie ID, but then if you don't know about the Movie object, you'd be doing this, which doesn't make sense:
movie = Movie.new("Titanic", "1997", "0120338")
movie.imdb_url(movie.movieID)
What would be the correct way to organise this code?
Upvotes: 0
Views: 341
Reputation: 54734
You would only need to extract this code into a separate module if you were to use it in multiple classes. I can however reenact the wish to split up a large model into several small chunks.
You could for example establish a protocol that the including class must adhere to and leave it up to the including class where the id comes from. In the following example, the including class must implement the method imdb_id
which is supposed to return the id that will be used for the url:
module IMDBMovieInfo
def imdb_id
raise NotImplementedError, 'including class needs to override imdb_id'
end
def imdb_url
"http://www.imdb.com/title/tt#{imdb_id}/"
end
end
class Movie
include IMDBMovieInfo
def imdb_id
self.movieID
end
attr_accessor :name
attr_accessor :year
attr_accessor :movieID
end
# In another classs
# (suppose IMDB lists computer games in the future)
class ComputerGame
include IMDBMovieInfo
def imdb_id
self.gameID
end
attr_accessor :name
attr_accessor :year
attr_accessor :gameID
end
I must however say that I find this whole extracting into mixins a bit clumsy. Another way would be to create a utility class that knows how to build an url but not where the id comes from:
class IMDBUtil
def initialize(imdb_id)
@imdb_id = imdb_id
end
def imdb_url
"http://www.imdb.com/title/tt#{@imdb_id}/"
end
end
class Movie
include IMDBMovieInfo
def imdb_url
IMDBUtil.new(self.movieId).imdb_url
end
attr_accessor :name
attr_accessor :year
attr_accessor :movieID
end
To wrap this up, here's a great blog post from CodeClimate on how to refactor fat Rails models.
Upvotes: 2
Reputation: 3509
In respect to your comment I would say, that the IMDBMovieInfo module shouldn't have a function that needs a movieID. You could just move it to your Movie class.
Upvotes: 1