9573

How do I apply the Law of Demeter to this?

Question:

I have an admittedly ugly query to do, to find a particular role related to the current role. This line produces the correct result:

@person_event_role.event_role.event.event_roles. joins(:mission_role).where(:mission_roles => {:title => 'Boss'}). first.person_event_roles.first.person

(You can infer the associations from the plurality of those calls)

The only way to get this information requires a ton of knowledge of the structure of the database, but to remove the coupling... It would require filling in a bunch of helper functions in each step of that chain to give back the needed info...

Answer1:

I think the thing to do here is to create the helper functions where appropriate. I'm unclear what the beginning of your association chain is here, but I'd probably assign it a method #event that returns event_role.event. From there, an event has an #boss_role, or whatever makes sense semantically, and that method is

event_roles.joins(:mission_role).where(:mission_roles => {:title => 'Boss'}).first

Finally, also on the Event model, there's a #boss method, which gets

boss_roles.first.person_event_roles.first.person

So, your original query becomes

@person_event_role.event.boss

Each leg of the chain is then self-contained and easy to understand, and it doesn't require the beginning of your chain to be omniscient about the end of it. I don't fully comprehend the full reach of these associations, but I'm pretty sure that just breaking it into three or four model methods will give you the clean reading and separation of concerns you're looking for. You might even break it down further for additional ease of reading, but that becomes a question of style.

Hope that helps!

<em>The following is by the original questioner</em>

I think I followed this advice and ended up with:

@person_event_role.get_related_event_roles_for('Boss').first.filled_by.first #person_event_role: def get_related_event_roles_for(role) event.event_roles_for(role) end def event event_role.event end #event: def event_roles_for(role) event_roles.for_role(role) end #event_role: scope :for_role, lambda {|role| joins(:mission_role).where(:mission_roles => {:title => role})} def filled_by person_event_roles.collect {|per| per.person} end

Recommend

  • Dependency injection, delayed injection praxis
  • junit: how to avoid false positives when using forkMode=“once”?
  • Attaching a fixed, transparent, header to a ListView?
  • byebug, next into application code only
  • Dependable views in Ember
  • Data Access from Entity framework works during debugging but not on live
  • Most efficient way to move table rows from one table to another
  • Open Existing DB in MySQL WorkBench
  • Sensibility of combined Maven/Ant+Ivy build management for dual platform Desktop/Android deployment?
  • abstracting over a collection
  • Bootstrap (v3.3.4) glyphicons not displayed in IE when refresh page (F5)
  • Pycharm: Marking a folder as 'sources root' is not recursive for subfolders
  • TextToSpeech.setEngineByPackageName() triggers NullPointerException
  • Sequential (transactional) API calls in angular 4 with state management
  • WPF ICommand CanExecute(): RaiseCanExecuteChanged() or automatic handling via DispatchTimer?
  • What's the purpose of QString?
  • rspec simple example getting error on request variable in integration test
  • onBackPressed() not being executed
  • With Hadoop, can I create a tasktracker on a machine that isn't running a datanode?
  • How to attach a node.js readable stream to a Sendgrid email?
  • Admob requires api-13 or later can I not deploy on old API-8 phones?
  • Unity3D & Android: Difference between “UnityMain” and “main” threads?
  • Exception “firebase.functions() takes … no argument …” when specifying a region for a Cloud Function
  • How to do unit test for HttpContext.Current.Server.MapPath
  • Regex thinks I'm nesting, but I'm not
  • What is the “return” in scheme?
  • Spray.io: When (not) to use non-blocking route handling?
  • DirectX11 ClearRenderTargetViewback with transparent buffer?
  • Does CUDA 5 support STL or THRUST inside the device code?
  • How to extract text from Word files using C#?
  • How to check if every primary key value is being referenced as foreign key in another table
  • Sending data from AppleScript to FileMaker records
  • Why is the timeout on a windows udp receive socket always 500ms longer than set by SO_RCVTIMEO?
  • Web-crawler for facebook in python
  • PHP: When would you need the self:: keyword?
  • How to disable jQuery.jplayer autoplay?
  • Unit Testing MVC Web Application in Visual Studio and Problem with QTAgent
  • How to get Windows thread pool to call class member function?
  • How to get NHibernate ISession to cache entity not retrieved by primary key
  • Unable to use reactive element in my shiny app