【问题标题】:Polymorphic and has_one association多态和 has_one 关联
【发布时间】:2015-12-12 00:44:40
【问题描述】:

我在我的应用中设置了多态关联。图片既属于记分牌模型,也属于可绘制的用户模型。每个记分牌和用户都有一张图片。我还有嵌套路由,其中​​图片资源嵌套在用户和记分牌资源中。

用户的路由文件:

resources :users do
  resources :picture
end

resources :account_activations, only: [:edit]
resources :password_resets, only: [:new, :create, :edit, :update]

resources :conversations, only: [:index, :show, :destroy] do
  member do
    post :reply
    post :restore
    post :mark_as_read
  end

  collection do
    delete :empty_trash
  end
end

记分牌的路线文件:

resources :scoreboards do 
  member do
    put :favourite
    get :deleteteams
    get :deleteschedules
  end

  resources :invitations, only: [:new, :create]
  resources :comments
  resources :teams, only: [:edit, :create, :destroy, :update]
  resources :schedules 
  resources :picture
end

我已经设置了一个图片控制器。代码如下。

class PictureController < ApplicationController
  before_filter :load_pictureable

  def new 
    @picture = @pictureable.build_picture                              
  end                                               

  def create
  end

  def destroy
  end

  private

  def picture_params
    params.require(:picture).permit(:picture)
  end

  def load_pictureable
    klass = [User, Scoreboard].detect { |c| params["#{c.name.underscore}_id"] }
    @pictureable = klass.find(params["#{klass.name.underscore}_id"]) 
  end
end                           

我的新表格如下:

 <div id= "uploadphoto">
   <%= form_for([@pictureable, @picture], url: scoreboard_picture_path, html: {multipart: true}) do |f| %>
     <%= f.file_field :picture, accept: 'image/jpeg,image/gif,image/png', id: "files", class: "hidden" %>
     <label for="files" id="picture"><h4 id="picturetext">Click Here to Upload Picture</h4></label>
       <div class="modal" id="modal-1">
         <div class="modal-dialog">
           <div class="modal-content">
             <div class="modal-header">Position and Crop your Image</div>
             <div class="modal-body">
               <div class="upload-preview">
                <img id="image" /></img>
               </div>
               <%= f.submit "upload photo" %>
             </div>
           <div class="modal-footer"> Click Anywhere Outside the box to Cancel</div>
         </div>
       </div>
     </div>
  <% end %>
</div>

我遇到的问题是 URL。这给了我以下错误。

No route matches {:action=>"show", :controller=>"picture", :scoreboard_id=>"13"} missing required keys: [:id]

我不确定为什么它会将我重定向到 show 操作,我认为它可能是嵌套路由。我不知道问题出在哪里。我以为我已经通过传递以下 URL new_scoreboard_picture_path 解决了它。但是,当我按下上传照片时,它会带我回到同一个 URL。这是有道理的,因为我在新表单中明确说明了 URL。然而,这是不正确的。如果有人可以帮助我找出问题所在,那将是一个很大的帮助。我只包含了相关代码。但是,如果我遗漏了什么,请告诉我。关于我为什么会收到此错误的任何解释也将澄清我的过程。这是第一次使用多态关联。任何形式的帮助都会很棒!

【问题讨论】:

  • 请遵循here 中的rails 控制器命名约定。你能从浏览器粘贴呈现的表单 HTML 代码吗?
  • 如果你也能显示routes.rb代码会有所帮助
  • @Jay-ArPolidario 我已经编辑了我的原始问题,并包含了记分牌和用户的所有相关路线文件。
  • 也许你在scoreboard_picture_path 中缺少新的-> new_scoreboard_picture_path ... %>?
  • @Jay-ArPolidario,我之前尝试过。它可以工作,但是当我提交表单时出现错误。当我尝试进行发布请求时,该 URL 不起作用。例如,如果我转到 URL users/1/picture/new。它可以工作,但是当我提交表单时,它会严格地将我带回 new_scoreboard_picture_path。

标签: ruby-on-rails ruby


【解决方案1】:

我会使用继承和两个单独的控制器来代替:

# the base controller
class PicturesController < ApplicationController
  before_action :load_pictureable

  def new 
    @picture = @pictureable.build_picture                              
  end                                               

  def create
    @picture = @pictureable.build_picture
    if @picture.save
      do_redirect
    else
      render_errors
    end
  end

  def destroy
    # ...
  end

  private

  def picture_params
    params.require(:picture).permit(:picture)
  end

  # Finds the picturable based on the module name of the class
  # for examples `Pets::PicturesController` will look for
  # Pet.find(params[:pet_id])
  def find_pictureable
    # this looks at the class name and extracts the module name
    model_name = self.class.deconstantize.singularize
    @pictureable = model_name.constanize.find(params["#{model_name}_id"])
  end

  # subclasses can override this to whatever they want
  def do_redirect
    redirect_to @pictureable
  end

  # subclasses can override this to whatever they want
  def render_errors
    render :new
  end
end

然后设置路线:

resources :users do
  resource :picture, controller: 'users/pictures'
end

resources :scoreboards do
  resource :picture, controller: 'scoreboards/pictures'
end

由于用户/记分板只能有一张图片,我们使用resource 而不是resources。这为单一资源设置了路线。使用rake routes 亲自查看差异。例如,您使用POST /users/:user_id/picture 创建图片。

然后我们设置子控制器:

# app/controllers/users/pictures_controller.rb
class Users::PicturesController < PicturesController
end

 # app/controllers/scoreboards/pictures_controller.rb
class Scoreboards::PicturesController < PicturesController
end

这允许高度自定义,而不会出现混乱的if/elseswitch 语句。这也可以防止恶意用户通过params[:user_id] 来操纵用户图片。永远不要使用用户输入来确定类或数据库表。

你也不需要显式指定表单url:

<%= form_for([@pictureable, @picture], html: {multipart: true}) do |f| %>

将使用users_picture_path(user_id: @pictureable.id) 或相同的记分牌。

【讨论】:

  • 为简洁起见,我没有添加它,但您应该考虑一个清理步骤,删除孤立的图片记录。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多