如何在一个模型从控制器验证,数据(How to validate in a model, data

2019-07-18 04:27发布

所以我认为会从另一个Rails应用程序控制器中的拉一些数据让叫它ExampleController,我希望让向导移动到其下一步骤之前,以验证它在我的模型在那里,我不能完全弄清楚如何我应该做的事( 我知道,直接从控制器到模型中得到这个数据违反了MVC我正在寻找最好的解决方法,从控制器得到我的数据 )。 该数据必须来自控制器得到它被包含在ApplicationController中,但是我能做到这一点的Awizard控制器如果这是比较容易的方法。 (我也不能使用宝石)

请提供某种暗示的问题,而不是为什么,这不是做的事情我知道,已经以正确的方式进行说明,但不能做到这一点的另一种方式。


示例性控制器

这应该不是呈现数据,然后检查一下是不是空白的其他地方?

class ExampleController < ApplicationController

  def valid_data?            
    data = #data could be nil or not
    if data.blank?
      return false
    else
      return true
  end

end

我的模型- (型号/ awizard.rb)

如何使用valid_data? 从示例性控制器的方法? 这里我的验证。

class AWizard
include ActiveModel::Validations
include ActiveModel::Conversion
include ActiveModel::Dirty
include ActiveModel::Naming

#This class is used to manage the wizard steps using ActiveModel (not ActiveRecord)

attr_accessor :id
attr_writer :current_step  #used to write to current step
define_attribute_methods [:current_step] #used for marking change

validate :first_step_data, :if => lambda { |o| o.current_step == "step1" };

def first_step_data
  #What should i put here to check the valid_data? from the examplecontroller
end

def initialize(attributes = {})
   attributes.each do |name, value|
     send("#{name}=", value)
   end
end

def current_step
  @current_step || steps.first
end

def steps
  %w[step1 step2 step3] #make list of steps (partials)
end

def next_step
  current_step_will_change! #mark changed when moving stepped
  self.current_step = steps[steps.index(current_step)+1] unless last_step?
end

def previous_step
  current_step_will_change! #mark changed when moving stepped
  self.current_step = steps[steps.index(current_step)-1] unless first_step?
end

def first_step?
  current_step == steps.first
end

def last_step?
  current_step == steps.last
end

def all_valid?
  steps.all? do |step|
    self.current_step = step
    valid?
  end
end

def step(val)
  current_step_will_change!
  self.current_step = steps[val]
end

def persisted?
  self.id == 1
end

end

或者我需要把它添加到这个观点?

(/views/awizard/_step1.html.erb)

<div class="field">
  <%= f.label 'Step1' %><br />
  #This is the step I want to validate
</div>

Answer 1:

我也许误解了问题,因为我的答案很简单。 然而这里的不诉诸元编程解决方案,但这样的事实向导(类对象不是它创建)是一个单/常数。

class ExampleController < ApplicationController

  def valid_data?            
    data = #data could be nil or not
    result = data.blank?
    Awizard.valid_data= result
    result
  end

end

class Wizard
  cattr_accessor :valid_data


  def valid_data?
    self.class.valid_data
  end
end

如果当然ExampleController#valid_data必须在使用向导通过step_one玩之前已被调用。

UPDATE:推理全局状态问题

(由@Valery Kvon升起)

的论点是,向导是全局的应用和@wizard实例将依赖于全局状态,因此严重包封。 但数据显示,从其他网站来了, 您的应用程序的范围gloabl。 因此,有与向导beeing一个保存数据不匹配。 相反它可以被看作是一个特征。

一个例子。 奇才魔术只在满月高效。 应用SkyReport发送数据:

:full_moon => true

它会影响在第1阶段所有的向导,如果他们需要去他们的权力的第二步。 因此,依靠的全局状态Wizard.valid_data? 正是我们想要的...

但是 ,如果每个向导有个人信息从甘道夫的应用即将到来,那么我们会想INFORCE甘道夫数据的调用,但随后该解决方案更简单:

# in example_controller.rb
before_filter :set_wizard_data, :only => [:create, :update]
....
def set_wizard_data
  @wizard = Wizard.find params[:id]
  @wizard.valid_data= valid_data
end

但是,这又意味着Gandalf.app知道(什么东西)的@wizard和问题是如何呈现的,数据从其他网站来是相当无关!

这里的问题是,我们不知道有足够的了解应用程序,它的需求和潜在的逻辑来决定什么是好还是不好?



Answer 2:

与模型共享控制器级别数据的唯一方法是通过外部访问。 使用元编程,你可以欺骗的方式将它传递给一个模型实例。

调节器

def valid_data?            
  data = #data could be nil or not
  result = data.blank? ? false : true
  instance_eval <<-EOV
    def AWizard.new(*args)
      super(*args).tap {|aw| aw.external_valid = #{result}}
    end
  EOV
  result
end

模型

class AWizard
  attr_accessor :external_valid

  def initialize(attributes = {})
    attributes.each do |name, value|
      send("#{name}=", value)
    end
  end

  validate :first_step_data, :if => lambda { |o| o.current_step == "step1" };

  def first_step_data
    # :external_valid would be true or false according to a valid_data?. Nil would be if valid_data? has not been called
    if external_valid == false
      errors.add ...
    end
  end
end


Answer 3:

你可以从控制器传递数据作为参数,以在模型中的验证方法。

在您的模型/ awizard.rb

def valid_for_step_one?(some_external_data)
  #validation logic here
end

所以,在你的控制器,你可以可以致电:

model.valid_for_step_one?(data_from_controller)

这也将是很好,如果你可以让你从控制器获取数据的描述。 它是如何与模型awizard?

因为另一个选择是设置外部数据作为模型的一个属性。 然后你就可以在你的验证功能,使用它从那里。



Answer 4:

于是,我就编辑和添加到@charlysisto问题,因为这是最接近的答案,但它没有工作,所以这里是我使用的解决方案,因为建议的答案是从控制器将数据发送到模型(虽然答案冷落使用视图调用控制器的方法),这里是我的解决办法

模型 -建模/ awizard.rb

class Awizard
  include ActiveModel::Validations

  cattr_accessor :valid_data

  validate :data_validation :if => lambda { |o| o.current_step == "step1" }

  def data_validation
    if self.valid_data == false || self.valid_data.blank?
      errors.add(:valid_data, "not found")
    end
  end

  #Other wizard stuff

end

查看 - awizard / _step1.html.erb

<div class="field">
  <% f.label "valid data? %>
  <% @_controller.valid_data %> #Call controller method to send data to model
</div>

调节器

class AwizardController < ApplicationController

  def valid_data
    data = #data from elsewhere
    if !data.blank?
      Awizard.valid_data = true
    else
      Awizard.valid_data = false
  end

end


文章来源: How to validate in a model, data from a controller