5

そのため、コントローラー内の別の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

私のモデル-(models / 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>

4

4 に答える 4

2

私の答えは単純なので、私はその質問を誤解したかもしれません。ただし、これはメタプログラミングに頼らないソリューションですが、ウィザード(作成するオブジェクトではないクラス)がシングルトン/定数であるという事実に基づいています。

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

もちろん、step_oneを渡すウィザードを試す前に、ExampleController#valid_dataが呼び出されている必要があります。

更新:グローバルな状態の問題についての推論

(@Valery Kvonによって発生)

ウィザードはアプリケーションに対してグローバルであり、@ widgetインスタンスはグローバル状態に依存するため、カプセル化が不十分であるという議論があります。ただし、別のサイトからのデータは、アプリの範囲内グロアブルです。したがって、データを保持しているウィザードとの不一致はありません。それどころか、それは特徴と見なすことができます。

一例。ウィザードの魔法は満月でのみ効果的です。アプリケーションSkyReportはデータを送信します:

:full_moon => true

パワーのステップ2に進む必要がある場合、ステージ1のすべてのウィザードに影響します。したがって、のグローバルな状態に依存するWizard.valid_data?ことは、まさに私たちが望んでいることです...

ただし、各ウィザードにガンダルフのアプリケーションからの個人的なメッセージがある場合は、ガンダルフのデータの呼び出しを強制する必要がありますが、解決策はさらに簡単です。

# 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(の何か)を知っていることを意味し、問題がどのように提示されるかから、他のサイトからのデータはかなり不可知論的です!

ここでの問題は、アプリ、その要件、および何が良いかどうかを判断するための基礎となるロジックについて十分に理解していないことです...

于 2013-01-16T13:16:56.903 に答える
1

コントローラレベルのデータをモデルと共有する唯一の方法は、外部アクセサを使用することです。メタプログラミングを使用すると、それをモデルインスタンスに渡す方法をだますことができます。

コントローラ

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
于 2013-01-16T10:06:57.443 に答える
0

コントローラからのデータをパラメータとしてモデルの検証メソッドに渡すことができます。

あなたのmodels/awizard.rbで

def valid_for_step_one?(some_external_data)
  #validation logic here
end

これで、コントローラーで次のように呼び出すことができます。

model.valid_for_step_one?(data_from_controller)

また、コントローラーから取得しているデータの説明を提供できればよいでしょう。モデルウィザードとどのように関連していますか?

別のオプションは、モデルの属性として外部データを設定することです。次に、そこから検証関数で使用できます。

于 2013-01-16T08:50:34.710 に答える
0

答えに最も近いので@charlysisto質問を編集して追加しようとしましたが、機能しませんでした。これが私が使用した解決策です。答えはコントローラーからモデルにデータを送信することでしたが、ビューを使用してコントローラーメソッドを呼び出すために省略された回答)これが私の解決策です

モデル-models/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
于 2013-01-17T00:22:56.230 に答える