2014-04-23 17 views
-1

在我的通讯表子句我有一些列:update_attribute使用其中红宝石

id | UserID | CommunicationMode | CommunicationDetail | Private 
1 | 1  | Phone    | 123456789   | 1 
2 | 1  | Email    | [email protected]   | 1 

而且我想用更新列值where子句中使用循环象下面这样:

create 
    @user_communication=Communication.where(:UserID => current_user.id) 
    if [email protected]_communication.blank? 
     @user_communication.each do |c| 
     if params[:ChkBx_Phone].to_i == 1 
      c.where("CommunicationMode == 'Phone'").update_attribute(:Private, "1") 
     elsif params[:ChkBx_Phone].to_i == 0 
      c.where("CommunicationMode == 'Phone'").update_attribute(:Private, "0") 
     end 
     if params[:ChkBx_Email].to_i == 1 
      c.where("CommuicationMode == 'Email'").update_attribute(:Private, "1") 
     elsif params[:ChkBx_Email].to_i == 0 
      c.where("CommunicationMode == 'Email'").update_attribute(:Private, "0") 
     end 
     end 
    end 
end 

我想检查上面,如果Phone复选框被选中然后它更新Private列值1其他0其中CommunicationMode is Phone和电子邮件我想检查,如果Email复选框是c hecked那么它更新Private柱与价值1其他0其中CommunicationMode is Email

及以下PhoneEmail复选框:

<table> 
    <% @user_communication.each do |c| %> 
      <tr> 
       <td> 
        <% if c.CommunicationMode == "Phone" and c.Private.to_s == "1" %> 
          <input type="checkbox" name="ChkBx_Phone" 
         id="ChkBx_Phone" value="1" checked = "checked"> 
          <%= label(:lb_Phone, "Phone") %> 
        <% elsif c.CommunicationMode == "Phone" and c.Private.to_s == "0" %> 
           <%= check_box_tag 'ChkBx_Phone' %> 
           <%= label(:lb_Phone, "Phone") %> 
        <% end %> 
       </td> 
      </tr> 
      <tr> 
       <td> 
        <% if c.CommunicationMode == "Email" and c.Private.to_s == "1" %> 
         <input type="checkbox" name="ChkBx_Email" 
         id="ChkBx_Email" value="1" checked = "checked"> 
         <%= label(:lb_Email, "Email") %> 
        <% elsif c.CommunicationMode == "Email" and c.Private.to_s == "0" %> 
         <%= check_box_tag 'ChkBx_Email' %> 
         <%= label(:lb_Email, "Email") %>      
        <% end %> 
       </td> 
      </tr> 
    <% end %> 
</table> 

但我得到以下错误:

undefined method `where' for #<Communication:0x4bc5490> 

但是,当我正在使用以下代码:

create 
    @user_communication=Communication.where(:UserID => current_user.id) 
    if [email protected]_communication.blank? 
     @user_communication.each do |c| 
     if params[:ChkBx_Phone].to_i == 1 
      puts "Hassan2" 
      c.update_attribute(:Private, "1") 
     elsif params[:ChkBx_Phone].to_i == 0 
      puts "Ali2" 
      c.update_attribute(:Private, "0") 
     end 
     end 
    end 
end 

其工作正常,但它更新Private columnPhoneEmail,我只检查了Phone复选框。 请建议我,等待您的回复。 谢谢。

回答

0

金士顿说,当你通过@user_communication访问集合,该块中的c变量实际上是一个具体的Communication对象,而不是一个ActiveRecord::Relation对象,这是包含.where查询方法。

此外,我还注意到一些其他问题。有些,我不能直接帮助你解决,因为我不知道你的系统是如何工作的,但是我会为你指出它们并试图提出一个替代方案,希望你能找到解决它们的最好方法。您系统的要求。

关于create方法,有两种方法会有相同的最终结果,但其中一个我会认为是“天真的方法”。我要展现天真的做法只给你一个直接的替代方案/回答您发布的第一个创建方法,所以你可以看到的差别,并找出最佳的解决方案:

幼稚的做法

def create 
    @user_communication=Communication.where(:UserID => current_user.id) 

    # Transaction so we don't execute X number of individual update statements 
    Communication.transaction do 

    @user_communication.each do |c| 

     if c.CommunicationMode == "Phone" 
     # Note: Its not necessary to use the ternary operator if you're not 
     # comfortable with it, however it can save you a few lines of code. 
     c.update(Private: (params[:ChkBx_Phone].to_i == 1 ? "1" : "0")) 
     elsif c.CommunicationMode == "Email" 
     c.update(Private: (params[:ChkBx_Email].to_i == 1 ? "1" : "0")) 
     end 

    end # end communication loop 

    end # end transaction 
end 

这将通过所述Communication对象对于该用户ID迭代,并更新每一个基于其CommunicationMode值时,它设置为1或0,这取决于两个复选框的值。您将在日志中看到的是您收集的每个Communication对象的几个单独的UPDATE语句。通常情况下,数据库会立即执行UPDATE语句,因为更新被封装在自己的事务中,因此,如果您有大量记录,则随着时间的推移这会变得相当昂贵。所以为了避免这个问题,正如你所看到的,我把整个操作都包装在一个事务中,因此,更新只在最后被提交;这样更有效率(您可以自己做一些实验来验证这一点;您应该能够看到有和没有事务包装器的明显时间差异)。

而现在,“潜在的”更好的方法:

的“潜在的”更好/更小天真的做法

这将执行只有两个UPDATE语句(你也可以包装在如果你喜欢交易)。这应该比上述方法更快执行,并且可以节省更多的代码。

请注意,这种方法和天真的方法都可以移至Communication模型中的一种方法,以将重型模型相关操作保留在控制器之外。

在视图代码的另一个问题,你似乎是迭代一个集合@user_communication,在其中您要创建一个复选框为每个对象:

<input type="checkbox" name="ChkBx_Email" id="ChkBx_Email" value="1" checked = "checked"> 

因此,如果该集合中有五个对象,则会看到五个复选框的列表。由于你命名这个输入的方式,只有其中一个值被发送(我相信它通常是DOM中的“最后”输入)。换句话说,如果您点击第一个复选框“打开”,但保留最后一个复选框,则复选框的值将“关闭”。我有一种强烈的感觉,这可能不是你希望你的系统行为的方式。也许你会想把这些复选框放在循环之外(上图),因为它们本身并没有任何关系。

此外,未经检查的复选框永远不会发送到服务器。如果您取消选中该复选框,则行params[:ChkBx_Phone].to_i == 1将会崩溃,因为params[:ChkBx_Phone]为零,并且您将在零对象上调用to_iThis answer向您显示此解决方案的替代方案。在你的情况,你会希望确保Rails的助手标签,如check_box_tag,和hidden_field_tag,像这样:

<%=hidden_field_tag 'ChkBx_Phone', '0'%> 
<%=check_box_tag 'ChkBx_Phone', '1', true %> 

其结果是,如果该复选框是因为相同的存在下去,命名隐藏字段输入,服务器将始终接收此参数的值。

0

在你的代码

@user_communication.each do |c|  
# Your logic 
end 

你循环@user_communication然后c变量将包含Communication objectActive record relation,那么你正在做c.where(),C含有Communication object。但是。其中Active record relation .so它是抛出错误。