在我的通讯表中,我有一些专栏:
id | UserID | CommunicationMode | CommunicationDetail | Private
1 | 1 | Phone | 123456789 | 1
2 | 1 | Email | abc@abc.com | 1
我想使用where子句使用如下所示的循环来更新列值:
create
@user_communication=Communication.where(:UserID => current_user.id)
if !@user_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
复选框,则会检查是否会更新Private
列,其值为1
,其他0
其中CommunicationMode is Email
以下是Phone
和Email
复选框:
<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 !@user_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 column
Phone
和Email
的{{1}}值,我只检查了Phone
复选框。
请建议我,等待你的回复。
感谢。
答案 0 :(得分:0)
在您的代码中
@user_communication.each do |c|
# Your logic
end
您循环@user_communication
然后c
变量将包含Communication object
而不是Active record relation
,那么您正在执行c.where()
,c包含Communication object
。但是 .where Active record relation
。所以它会抛出错误。
答案 1 :(得分: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
这将遍历该用户ID的Communication
个对象,并根据其CommunicationMode
值更新每个对象,将其设置为1或0,具体取决于两者的值复选框。您将在日志中看到的内容是集合中每个UPDATE
对象的几个Communication
语句。通常,数据库会立即执行UPDATE
语句,因为更新包含在它们自己的事务中,因此,如果您有大量记录,这会随着时间的推移而变得相当昂贵。因此,为了避免这个问题,你可以看到我已经将整个操作包装在一个事务中,因此,更新只在最后提交;这样效率更高(您可以自己进行一些实验来验证这一点;无论是否使用事务包装器,您都应该能够看到明显的时间差异。)
现在,“潜在”更好的方法:
“可能”更好/更不天真的方法
... other method code
Communication.where(UserID: current_user.id, CommunicationMode: "Phone").update_all(Private: (params[:ChkBx_Phone].to_i == 1 ? "1" : "0") )
Communication.where(UserID: current_user.id, CommunicationMode: "Email").update_all(Private: (params[:ChkBx_Email].to_i == 1 ? "1" : "0") )
这将只执行两个UPDATE
语句(如果您愿意,也可以在事务中包装)。这应该比上述方法更快地执行,并为您节省更多的代码。
请注意,这个和天真的方法都可以移动到Communication
模型中的方法,以便将与模型相关的大量操作保留在控制器之外。
另一个注意事项
在您的视图代码中,您似乎是对集合@user_communication
进行迭代,您在其中为每个对象创建一个复选框:
<input type="checkbox" name="ChkBx_Email" id="ChkBx_Email" value="1" checked = "checked">
因此,如果该集合中有五个对象,您将看到一个包含五个复选框的列表。由于您命名此输入的方式,只有一个值被发送(我相信它通常是DOM中的“最后”输入)。换句话说,如果您点击第一个复选框“on”,但保留最后一个“off”,则复选框的值将为“off”。我有一种强烈的感觉,这可能不是您希望系统的行为方式。也许您会希望将这些复选框放在循环之外(上图),因为它们似乎与Communication
对象本身没有任何关系。
此外,永远不会向服务器发送未选中的复选框。如果您取消选中该复选框,则params[:ChkBx_Phone].to_i == 1
行将会崩溃,因为params[:ChkBx_Phone]
为零,并且您将在nil对象上调用to_i
。 This answer向您展示了此解决方案的替代方案。在您的情况下,您需要确保Rails帮助程序标记,例如check_box_tag
和hidden_field_tag
,如下所示:
<%=hidden_field_tag 'ChkBx_Phone', '0'%>
<%=check_box_tag 'ChkBx_Phone', '1', true %>
因此,如果取消选中该复选框,由于存在同名隐藏字段输入,服务器将始终接收此参数的值。