Ian Ellis Ian Ellis - 1 year ago 55
Ruby Question

Ruby on Rails: Creating a link based on new database entry

I'm in the process of updating a website I made almost 2 years ago. It was my first real website and I made some mistakes (some more serious that others).

What apparently is one of my biggest is making database calls from the view.

I'm pretty damn sure there is a better way to do this:

Use Case:

  1. Someone fills out a form for a new subject, populating the Subject table, and they have been marked "enrolled", Subject.enrolled = 1

  2. Based on that, I now need to create a record in 5 other tables (such as Baseline)

  3. Downhill from here, here is my method

    • Determine if the record exist based on subject_id from Subject (sub)

      <$ if Baseline.where(subject_id: sub.subject_id).first != nil $>

    • If it does not exist, create the record, (otherwise display the link)

      <%= Baseline.create(subject_id: sub.subject_id) %>

  4. This all happens in the view, and creates a front-end table with links to each record in the process. So I'm creating records based on for-loop logic...

So I'm looking for direction. I don't want to guess how to do this - I'm pretty sure the model/controller should do this - I want to learn how to do it correctly. How do I create records automatically, based on a value in a table?

Thank you for your time.

Answer Source

Not quite sure how your domain and code looks like, but to answer this question: 'How do I create records automatically, based on a value in a table?', it seems that you could use ActiveRecord callbacks, like this:

class Subject < ActiveRecord::Base
  after_commit :create_baseline_if_enrolled, on: [:create, :update]


  def create_baseline_if_enrolled
    return unless enrolled?

    # enrolled? == true, you may create these models here

To answer your question: It depends :) This is just one possible solution. Another one would be to put such a custom logic in your SubjectsController and call it directly from the #create, #update methods. Both approaches have pros and cons. For example, abusing callbacks (anywhere) makes code less readable and harder to debug. On the other hand, putting such logic in controllers puts a burden on you that you have to remember about calling it if you happen to be editing subjects in other places (but is more explicit). Whichever way you choose, remember not to make your classes too fat, for example try to use service object pattern to separate such custom logic as soon as you feel like it is getting out of hand. :) And don't forget about tests - when things go wrong, tests make refactoring easier.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download