简体   繁体   English

多态和has_one关联

[英]Polymorphic and has_one association

I have set up a polymorphic association in my app. 我在我的应用程序中建立了一个多态关联。 A picture belongs to both a scoreboard model and a user model as pictureable. 图片属于可记分的记分板模型和用户模型。 Each scoreboard and user has_one picture. 每个计分板和用户都有一张图片。 I also have nested routes where pictures resource is nested inside a user and scoreboard resource. 我也有嵌套的路线,其中图片资源嵌套在用户和记分板资源中。

Routes File for the users: 用户的路由文件:

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

Routes file for the scoreboard: 计分板的路线文件:

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

I have setup a picture controller. 我已经设置了图片控制器。 The code is given below. 代码如下。

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                           

My new form is given below: 我的新表格如下:

 <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>

The problem I am having is with the URL. 我遇到的问题是URL。 This gives me the following error. 这给了我以下错误。

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

I am not sure why it redirects me to the show action, I assume its probably the nested routes.I don't know what the problem is. 我不确定为什么它会将我重定向到show动作,我认为它可能是嵌套的路线。我不知道问题出在哪里。 I thought I had resolved it by passing the following URL new_scoreboard_picture_path . 我以为我已经通过传递以下URL new_scoreboard_picture_path解决了它。 However, when I press upload photo, It would take me back to the same URL. 但是,当我按“上传照片”时,它将带我回到相同的URL。 This makes sense because I am explicitly stating the URL in the new form. 这是有道理的,因为我以新形式明确指出了URL。 However, that is incorrect. 但是,这是不正确的。 It would be a great help if someone could help me figure out what the issue is. 如果有人可以帮助我找出问题所在,那将是一个很大的帮助。 I have only included the relevant code. 我只包含了相关代码。 However, if i am missing anything please do let me know. 但是,如果我想念任何东西,请告诉我。 Any explanation as to why I am getting this error would also clarify my though process. 关于我为什么会收到此错误的任何解释也将阐明我的处理过程。 This is the first time working with polymorphic associations. 这是第一次使用多态关联。 Any sort of help would be great!! 任何形式的帮助都将很棒!

I would use inheritance and two separate controllers instead: 我将使用继承和两个单独的控制器来代替:

# 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

Then setup the routes: 然后设置路线:

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

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

Since a user/scoreboard can have only one picture we are using resource and not resources . 由于用户/记分板只能包含一张图片,因此我们使用的是resource而不是resources This sets up the routes for singular resource. 这将为单个资源设置路由。 Use rake routes to see the difference for yourself. 使用rake routes自己看看差异。 For example you create a picture with POST /users/:user_id/picture . 例如,您使用POST /users/:user_id/picture创建POST /users/:user_id/picture

We then setup the child controllers: 然后,我们设置子控制器:

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

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

This allows a high degree of customization without a jumble of if/else or switch statements. 这允许高度定制,而不会混杂if/elseswitch语句。 Also this safeguards against a malicious user passing params[:user_id] to manipulate a users picture. 这也可以防止恶意用户通过params[:user_id]来操纵用户图片。 You should never use user input to determine classes or database tables. 您永远不要使用用户输入来确定类或数据库表。

Also you do not need to explicitly specify the form url: 另外,您无需显式指定表单url:

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

Will use users_picture_path(user_id: @pictureable.id) or the same for scoreboards. 将对记分板使用users_picture_path(user_id: @pictureable.id)或相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM