rails form_with 中关联模型的路径问题

Posted

技术标签:

【中文标题】rails form_with 中关联模型的路径问题【英文标题】:Pathing issues in rails form_with for associated model 【发布时间】:2018-02-24 11:17:36 【问题描述】:

我正在处理一个项目,我必须分析文件中的数据,用户应该能够上传该文件。我有一个模型 InputFile,并选择为我的 Analysis 模型实现一个 analysis_facade,它捆绑了大部分功能。 这是模型

#app/models/analysis.rb
class Analysis < ApplicationRecord
  has_one :input_file, dependent: :destroy
end

#app/models/input_file.rb
class InputFile < ApplicationRecord
  belongs_to :analysis
  has_many :access_data, dependent: :destroy

  def uploaded_file=(file_field)
    self.name = File.basename(file_field.original_filename).gsub(/[^\w._-]/,'')
    self.content_type = file_field.content_type.chomp
    self.data = file_field.read
  end
end

我的 AnalysisController 和相应的外观模式来了

#app/controllers/analyses_controller.rb
class AnalysesController < ApplicationController
  before_action :set_analysis, only: :show

  def show
    @analysis_facade = AnalysisFacade.new(@analysis)
  end

  private

  def set_analysis
    @analysis ||= Analysis.create
  end
end

#app/facades/analysis_facade.rb
class AnalysisFacade
  attr_reader :analysis

  def initialize(analysis)
    @analysis = analysis
  end

  def new_input_file
    @input_file = analysis.build_input_file
  end

  def input_file
    @input_file ||= new_input_file
  end

  def access_data
    @access_data ||= analysis.input_file.access_data
  end
end

我的 InputFiles 控制器

#app/controllers/input_files_controller.rb
class InputFilesController < ApplicationController
  include LogFileScanner

  before_action :set_analysis, only: [:new, :create, :update]

  def new
    @input_file = Input_file.new
  end

  def create
    @input_file = @analysis.build_input_file(input_file_params)
    if @input_file.save
      access_data = scan(@input_file.data)
      @input_file.access_data.create(access_data)
    end
  end

  def update
    @input_file = @analysis.input_file
    if @input_file.update
      access_data = scan(@input_file.data)
      @input_file.access_data.update(access_data)
    end
  end

  private

  def input_file_params
    params.require(:input_file).permit(:uploaded_file, :analysis_id)
  end

  def set_analysis
    @analysis = Analysis.find(params[:input_file][:analysis_id])
  end
end

对于文件上传,我有这些观点

#app/views/analyses/show.html.erb
<%= render template: 'input_files/get' %>

#app/views/input_files/get.html.erb
<%= form_with model: [@analysis_facade.analysis, @analysis_facade.input_file], action: :update, html: multipart: true, class: 'form-horizontal center' do |form| %>
  <div class='form-group.new'>
    <% if false %>
      <%= form.hidden_field :analysis_id, value: @analysis_facade.analysis[:id] %>
    <% end %>
    <%= form.file_field 'uploaded_file' %>
    <%= form.submit "Upload", class: 'btn btn-default btn-primary' %>
  </div>
<% end %>

执行此操作会导致错误

undefined method `analysis_input_files_path' for #<#<Class:0x00007f1208040288>:0x00007f11f0d71d48>
Did you mean?  analysis_path

对于这个地方

<%= form_with model: [@analysis_facade.analysis, @analysis_facade.input_file], action: :update, html: multipart: true,
class: 'form-horizontal center' do |form| %>

这是为什么呢?我需要将 analysis_id 传递给 params 以创建新的 InputFile。但我希望它比手动添加 hidden_​​field 更干净,因为 model_with 应该提供此功能。我在这里想念什么?

另外:为什么 rails 会搜索 `analysis_input_files_path'?它显然是一个has_one关系,那么它不应该寻找analysis_input_file_path吗?

编辑:

#bin/rails routes

                     Prefix Verb   URI Pattern                                           Controller#Action
                   analyses GET    /analyses(.:format)                                   analyses#index
                            POST   /analyses(.:format)                                   analyses#create
               new_analysis GET    /analyses/new(.:format)                               analyses#new
              edit_analysis GET    /analyses/:id/edit(.:format)                          analyses#edit
                   analysis GET    /analyses/:id(.:format)                               analyses#show
                            PATCH  /analyses/:id(.:format)                               analyses#update
                            PUT    /analyses/:id(.:format)                               analyses#update
                            DELETE /analyses/:id(.:format)                               analyses#destroy
     input_file_access_data GET    /input_files/:input_file_id/access_data(.:format)     access_data#index
                            POST   /input_files/:input_file_id/access_data(.:format)     access_data#create
new_input_file_access_datum GET    /input_files/:input_file_id/access_data/new(.:format) access_data#new
          edit_access_datum GET    /access_data/:id/edit(.:format)                       access_data#edit
               access_datum GET    /access_data/:id(.:format)                            access_data#show
                            PATCH  /access_data/:id(.:format)                            access_data#update
                            PUT    /access_data/:id(.:format)                            access_data#update
                            DELETE /access_data/:id(.:format)                            access_data#destroy
                input_files GET    /input_files(.:format)                                input_files#index
                            POST   /input_files(.:format)                                input_files#create
             new_input_file GET    /input_files/new(.:format)                            input_files#new
            edit_input_file GET    /input_files/:id/edit(.:format)                       input_files#edit
                 input_file GET    /input_files/:id(.:format)                            input_files#show
                            PATCH  /input_files/:id(.:format)                            input_files#update
                            PUT    /input_files/:id(.:format)                            input_files#update
                            DELETE /input_files/:id(.:format)                            input_files#destroy
              analyses_show GET    / 

【问题讨论】:

【参考方案1】:

我是一个概念错误。我将立面模型更改为

class AnalysisFacade

  attr_reader :analysis

  def initialize(analysis)
    @analysis = analysis
  end

  def new_input_file
    @analysis.build_input_file
  end

  def input_file
    @analysis.input_file ||= new_input_file
  end

  def access_data
    @analysis.input_file.access_data
  end

end

视图现在像这样工作

<%= form_with model: @analysis_facade.input_file, html: multipart: true, class: 'form-horizontal center' do |form| %>
  <div class='form-group.new'>
    <%= form.file_field 'uploaded_file' %>
    <%= form.submit "Upload", class: 'btn btn-default btn-primary' %>
  </div>
<% end %>

【讨论】:

以上是关于rails form_with 中关联模型的路径问题的主要内容,如果未能解决你的问题,请参考以下文章

获取Rails模型中关联列的总和

如何对rails中关联记录的jquery数据表列进行排序

Rails form_with(remote:true)错误

Rails 5:form_for 与 form_with

Rails 6.1 将 submit_tag 链接到 form_with

如何在 laravel 中关联三个模型?