简体   繁体   中英

What's the proper way to do this in Rails?

So I've got two records from Model, a and b. I want to do this:

def do_codependant_stuff(a,b)
    a.attribute += b.attribute2
    b.attribute = b.stuff+a.stuff
end

I keep hearing fat model, skinny controller, and no business logic in views, so I've put this in my Model model. Based on what a user clicks in one of my views, I want to call do_codependant_stuff(a, b) or do_codependant_stuff(b,a).

I've been just using the basic crud controller actions up to this point, and I'm not quite sure how to make this happen. Do I add this logic to my ModelController update action? Because it's technically updating them, just in a more specific way. Or make another action in the controller? How do I call it/set it up? Most of the default new, update etc are somehow called behind the scenes based on their respective views.

And is updating two things at a time bad practice? Should I split the do_codependant_stuff method into two instance methods and call them on each record with the other as a parameter?

Thanks for reading.

Edit: Alright, real world code. I'm displaying on the home page of my app two pictures. The user selects the one they like most. The ratings of these pictures change based on a chess ranking algorithm. This is the relevant section of my picture class.

 class Picture < ActiveRecord::Base
   ...
   ...
        def expected_first_beats_second(picture first, picture second)
            1/(1+10**((second.rating-first.rating)/400))
        end
        def first_beat_second(picA,picB)
            Ea = expected_first_beats_second(picA,picB)
            picA.rating += 50*(1-Ea)
            picB.rating += 50*(-(1-Ea))

        end
    end

The partial I'm using for the view just displays two pictures at random so far with

<% picA = Picture.offset(rand(Picture.count)).first %>
<% picB = Picture.offset(rand(Picture.count)).first %>

<div class = "row">
    <div class = "col-md-5">
        <%= image_tag picA.url, :class => "thumbnail" %>
    </div>
    <div class = "col-md-5">
        <%= image_tag picB.url, :class => "thumbnail" %>
    </div>
</div>

I need to somehow link the onclick of those images to the method in the model.

Here's some code to get you started. Note the comments, they're ruby and rails best practices

Controller:

class PC < AC
  ...
  def compare
    # count query once, save the number
    count = Picture.count
    @pic_a = Picture.offset(rand(count)).first
    @pic_b = Picture.offset(rand(count)).first
  end

  def compare_submit
    # Note variables are snake cased, not camel cased
    pic_a = Picture.find(params[:winner_id])
    pic_b = Picture.find(params[:loser_id])
    pic_a.beats(pic_b)
    redirect to compare_pictures_path # Or wherever
  end
  ...
end

Any sort of querying should be done in the controller or model. You essentially should never directly access a model in your view. At this point your view has access to the instance variables set in the controller: @pic_a and @pic_b

View:

<%= link_to compare_submit_pictures_path(winner_id: @pic_a.id, loser_id: @pic_b.id) do %>
  <%= image_tag @pic_a.url, :class => "thumbnail" %>
<% end %>

<%= link_to compare_submit_pictures_path(winner_id: @pic_b.id, loser_id: @pic_a.id) do %>
  <%= image_tag @pic_b.url, :class => "thumbnail" %>
<% end %>

So we just linked to a new path (see routes below) that will pass two parameters: winner_id and loser_id so whichever picture the user clicks on you'll know which one they chose and which one they didn't choose.

Model:

class Picture < AR::Base
  # Method arguments don't need a type declaration
  def beats(loser)
    # Always lowercase variables
    ea = 1/(1+10**((loser.rating-self.rating)/400))
    self.rating += 50*(1-ea)
    loser.rating += 50*(-(1-ea))
    self.save
    loser.save       
  end
end

This explicitly uses self for clarity, which isn't necessary. Calling save or rating = ... implicitly calls it on self since we're in the context of an instance method on the picture Model.

Routes:

resource :pictures do
  collection do
    get :compare
    get :compare_submit
  end
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM