简体   繁体   中英

Voting in voter controller for multiple models passing polymorphic/duck typed object variable

I am trying to implement voting for various models: Character, Universe models. I have some vote buttons on their respective show templates via a single DRY rendered partial. This means I need to make that partial agnostic to the model when I pass that model to the controller logic that creates the vote record.

So yes, I am wondering if it is possible to have this kind of duck typed variable passing to a votes controller, rather than repeating the vote creation logic in each of the Character and Universe controller.

How do I make this sort of duck typed variable passing using path helpers, votes partials, and votes controllers? Or should I just repeat the code in each votable model?

FYI: Naturally, the votes is polymorphic to the two models. I am using acts_as_votable gem https://github.com/ryanto/acts_as_votable

_vote.html.haml

.vote-comment-buttons
  = link_to image_tag("upvote.png"), votes_upvote_path(), method: :post, remote: true
  %span=# @comment.get_upvotes.sum(:vote_weight)
  = link_to image_tag("downvote.png"), votes_downvote_path(), method: :post, remote: true

^ Do I pass a duck type variable to the paths?, If so, how/where do I define the duck type variable?

(Note: i'm trying to vote via AJAX, but feel free to ignore the ajax related code like remote: true)

character.rb

class Character < ActiveRecord::Base
  acts_as_votable # creates a polymorphic association with votes
end

universe.rb

class Universe < ActiveRecord::Base
  acts_as_votable # creates a polymorphic association with votes
end

votes_controller.rb

class VotesController < ApplicationController

  before_action :check_if_voted(@votable)

  def upvote
    #votable.vote_up current_user

  end

  def downvote(votable)
    #votable.vote_down current_user
  end
end

Iis it valid to have parameters on actions? or do you just use params[]?

Iis it valid to have parameters on actions? or do you just use params[]?

You can not have parameters at public actions, all the data should be parsed from params[]

How do I make this sort of duck typed variable passing using path helpers, votes partials, and votes controllers? Or should I just repeat the code in each votable model?

Assuming voting procedure is the same for both models, consider using concerns :

config/application.rb

 module YourApplicationName
   class Application < Rails::Application
     config.autoload_paths += %W(#{config.root}/app/controllers/concerns)
   end
 end

app/controllers/concerns/voting_controller.rb

module VotingController
  extend ActiveSupport::Concern

  included do
    before_filter :obtain_resources, only: [:upvote, :downvote]
  end

  def upvote
    # here goes your upvoting logics, something like
    # @object.liked_by user1, :vote_weight => 1
    # the @object variable has already been set in obtain_resource filter
    # other params should be catched up from the params hash
  end

  def downvote
    # here goes your downvoting logics
  end

  private
  def obtain_resources
    # here we retrieve the name of a particular controller which triggered this action
    model = controller_name.singularize.camelize.constantize
    @object = model.find(params[:id])
  end
end

In case you prefer using meaningful variable names instead of just @object , you can do this kind of thing:

# app/controllers/concerns/voting_controller.rb
def obtain_resources
  model = controller_name.singularize.camelize.constantize
  instance_name = controller_name.singularize
  # here you get @universe or @character
  instance_variable_set "@#{instance_name}", model.find(params[:id])
end

Then in your controllers you should include that concern:

class UniverseController < ApplicationController
  include VotingController
  # that's all, you should not implement voting actions here as they are included from VotingController
end

class CharactersController < ApplicationController
  include VotingController
end

You should also be sure to set appropriate routes in your config/routes.rb file, so that upvote and downvote actions exist in both of the controllers. As you could already understand, you should pass upvote_universe_path or upvote_characters_path to your partial to make this work (same for the downvoting). Each route should pass id of the object to controller's action.

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