在事务中使用if语句删除多个对象

时间:2016-05-25 21:33:40

标签: ruby-on-rails if-statement transactions conditional

我是一名初级开发人员试图编写代码,用于分隔用户拥有的蜂鸣声并发出另一个用户授权的蜂鸣声。

哔哔声来自用户拥有的设备。所有者可以授权其他用户使用该设备并接收他们自己的蜂鸣警报。这为我们提供了两种不同类型的哔声:拥有的哔哔声和授权的哔哔声。我希望授权用户能够同时删除多个蜂鸣事件并且只能删除自己的蜂鸣事件,而我希望所有者能够删除多个蜂鸣声以及那些蜂鸣声相应的事件。

我正在处理的应用程序非常庞大,并且在体系结构上已经设置了此功能,所有者只能删除一次哔声。

beep事件通过一个方法与一个单独的应用程序通信,该应用程序通过device_broker方法处理事件的删除。

我最终做的是一个带有if语句的事务,然后循环遍历每个迭代器,检查如果它是由用户拥有或授权的每个蜂鸣声。

我的问题是我的broker_mock测试没有收到任何参数。当我在代码上使用调试器时,这些方法似乎都有效,所以我很困惑。使用带有每个循环的if语句是个好主意吗?将它全部包装在一个事务中意味着如果一个小东西中断,它就不起作用。还有更好的选择吗?

感谢您可以放下任何智慧或光明。

  beeps_controller.rb

  def bulk_deletion
      BulkBeepRemover.run!(params[:beep_ids], current_user)
  end

  bulk_beep_remover.rb

  class BulkBeepRemover
    class Unauthorized < StandardError; end;
    attr_reader :beep_ids, :user, :beeps

    attr_accessor :owned_beeps, :unowned_beeps

    def self.run!(beep_ids, user)
      new(beep_ids, user).run!
    end

    def initialize(beep_ids, user)
      @beep_ids = beep_ids
      raise Unauthorized if user.nil?
      @user = user
    end

    def beeps
      @beeps ||= Beep.finished.find(beep_ids)
    end

    def device_broker
      @device_broker ||= $device_broker
    end

    attr_writer :device_broker

    def run!
      #handles deletion of the owned beeps
      Beep.transaction do
        beeps.each do |beep|
          if beep.device.is_owner?(user)
             beep.destroy
             remove_beep_event(beep.id)
          end
         # elsif beep.device.is_authorized?(user) logic goes here
        end
      end
    end

 private

  def remove_beep_event(beep_id)
    device_broker.publish('beep_deleted', { beep_id: beep_id })
  end

dings_spec.rb

  describe "POST /clients_api/beeps/bulk_deletion" do
    let(:user_id)        { user.id }

    let!(:shared_beep_1) { create(:beep, id: 33, device:       authorized_device, state: :completed) }
    let!(:shared_beep_2) { create(:beep, id: 34, device: authorized_device, state: :completed) }
    let!(:owned_beep_1)  { create(:beep, id: 35, device: owned_device, state: :completed) }
    let!(:owned_beep_2)  { create(:beep, id: 36, device: owned_device, state: :completed) }

    before do
      post "/clients_api/beeps/:beep_id/bulk_deletion",        default_params.merge(beep_ids: [shared_beep_1.id, shared_beep_2.id,     owned_beep_1.id, owned_beep_2.id], user_id: user.id)
      allow_any_instance_of(BulkBeepRemover).to receive(:device_broker).and_return(broker_mock)
    end

    context "the owner's array of beep ids" do
      let(:beep_id) { owned_beep_2.id }


      it "deletes the beeps" do
        expect { Beep.find(beep_id) }.to     raise_error(ActiveRecord::RecordNotFound)
      end

      it "publishes the owner beep_deleted event" do
        expect(broker_mock).to     have_received(:publish).with("beep_deleted", { beep_id: beep_id })
      end
    end
  end
end

1 个答案:

答案 0 :(得分:0)

您的/clients_api/beeps/:beep_id/bulk_deletion路线似乎没有:user_id参数。因此,传递user_id参数没有参数。

此外,参数名称:beep_id与测试中的用法不匹配,后者将其称为:beep_ids;这可能会或可能不会出现问题,但值得确保名称一致以避免冲突。

您在if区块内询问了each语句,根本没有问题;这在Ruby代码中很常见。您已经使用if声明找到了。

关于交易,您可以使用rescue保护交易冻结块,但 是否完全取决于一些考虑因素。

1)事务块的目的很重要,而且代码中并不明显。您必须确定事务是否严格用于更新数据库的效率(以减少SQL调用的数量),或者是否保持事务完整性。

2)您必须了解以这种方式使用rescue是否被认为是您组织中可接受的做法;它在一些组织中非常禁止。如果不允许,您必须采取措施确保在发生异常之前避免发生异常。一种方法是在执行操作之前询问是否安全执行操作,并且如果它不安全则避免这样做。

3)您必须知道,在没有提供适当反馈的情况下,无论出于何种原因,忽略在交易中删除哔声是否可以接受;或者,另一方面,确定适当的反馈机制是什么。无声地失败的进程并不是很珍贵。例如,如果有人要求删除蜂鸣声,并且删除成功,则可以认为已经删除了蜂鸣声;如果没有,那么应该以某种方式告知进程的用户它不是,以便他们可以采取适当的行动,即使该动作只是简单地在上游传递消息。

实际上,如果有关于交易使用的问题以及if是否可以(或)使用,您可能正在进入软件设计领域,您可能需要澄清关于你必须使用的目标和限制。这是软件开发人员的生活;每个简单的问题都有许多复杂的考虑因素。学会认真地认识和处理它们,你就会领先一步!