如何组织业务逻辑和js逻辑,在Rails中进行投票?

时间:2014-08-10 23:39:33

标签: ruby-on-rails design-patterns voting

在rails中,我想在点击投票按钮时处理视觉投票图标和数据库记录。看起来将这两个都放在一个权威位置(这样它们不会失去同步),而不是在不同文件中复制前端和后端的控制流逻辑似乎是个好主意。

有一些逻辑如下,我需要处理前端方面和后端方面。 他在轨道上做到这一点的最佳方法是什么?

有一项民意调查,有不同的选择。每个选项都有scope个ID。

以下代码处理只允许一个选项的选项的直观投票行为。

控制器调用的模型方法

if current_user voted_for? @votable
  @votable.unvote_by current_user
  @votable.vote_by current_user, scope: params[:vote_type] unless current_user voted_for? @votable, scope: params[:vote_type]
else
  @votable.vote_by current_user, scope: params[:vote_type]
end

现在这对后端很好,我需要前端。

资产javascript文件

// Detect if record was voted for by current user, obtain #id 
  // add class 'voted' to child with matching #id

$('#poll .option').on(click, ->

  if ($('this').first().class('voted') ) {
    $('this').first().removeClass('voted');
  } else if ( $('this').siblings('option').first().class('voted') ){
    $('this').siblings('option').first().removeClass('voted');        
  } else {
    $('this').first().addClass('voted');
  }

使用导轨remote: true链接可以正常使用吗?

html.haml

#poll
  = link_to (content_tag :div, class: @voted), vote_path(:vote_type)
  = link_to "", vote_path(vote_type: "2"), class=

使用acts_as_votable API在视图中有条件地设置类。使用CSS来设置'投票'

的样式

控制器

def show
  # can be moved to model

  if current_user.voted_on? @votable
    @voted = 'voted'
  else
    @voted = ''
  end

结束

我上面没有使用过ajax调用。我需要吗? 如果我使用ajax,上面的javascript似乎会很快变得非常混乱。 它也不会阻止多次投票,或者视觉投票与数据库中实际的投票不同步。

现在上面到目前为止重复了后端和前端的if / else控制流程。 但是将它们组合在一个js.erb文件中是否更好呢?

这就是为什么我认为将事物组合成一个处理正面和背面的js.erb可能会更好。但这似乎也不是好的设计。也许有一种方法可以使用ajax来进行更多验证并提高稳健性?无论如何,这都是不错的选择。只要它有效,那就很好。

似乎有一个自定义的js.erb文件不适合使用responds_with ...我很困惑。如何继续。


对于此问题中的多个问题,我们深表歉意。我只是想实现一个直观的投票系统,从不同来源获取信息并不容易。

提前致谢。

1 个答案:

答案 0 :(得分:1)

这是一个非常通用的问题。对于后端来说,你可以使用一些宝石来做到这一点,因为它会让你的生活更轻松,例如 acts_as_votable gem for rails。

然后将其包含在您的ActiveRecord模型中:

class Record < ActiveRecord::Base
  acts_as_votable
end

现在您将能够使用许多辅助方法,例如:

@record = Record.create!(attributes)
@record.liked_by @user1
@record.downvote_from @user2
@record.vote_by :voter => @user4, :vote => 'bad'
@record.vote_by :voter => @user5, :vote => 'like'

至于你的fronend,你可以发送一些类似于 link_to remote的Ajax请求:true form_for remote:true 。然后你可以使用RJS甚至在客户端使用jQuery手动执行此操作并更改div的状态。

我将在此处使用代码进行演示:

在控制器中,您将执行以下操作:

def vote
  @record = Record.find(params[:post_id])
  @record.liked_by current_user
end

HTML

<%= link_to 'like', vote_path(@record), class: 'vote', remote: true %>

JS

$('.vote')
  .on('ajax:send', function () { $(this).addClass('loading'); })
  .on('ajax:complete', function () { $(this).removeClass('loading'); })
  .on('ajax:success', function (data) { $(this).html(data.count); });