【问题标题】:Ruby on rails. Form for a nested model in a different view红宝石在铁轨上。不同视图中嵌套模型的表单
【发布时间】:2023-03-19 22:15:01
【问题描述】:

我已经与这个问题斗争了一段时间,但我无法弄清楚。我有一个使用设计的用户模型。用户可以上传歌曲,添加 youtube 视频等。

我试图让用户从设计edit registrations 视图中添加/删除歌曲和视频。

视频上传正常,但由于歌曲是播放列表的嵌套资源,属于用户,我想我有点糊涂了。

音乐在其相应页面上以相同的形式上传,但不是来自设计registration edit 视图。

路线:

  devise_for :users, controllers: { registrations: "users/registrations", sessions: "users/sessions" }

  resources :videos

  resources :playlists do
    resources :songs
  end

设计注册控制器:

   def edit
     @song = Song.new
     @video = Video.new
   end

设计编辑注册中的表格:

<div id="user-music-box">
  <p class="p-details-title"> Upload Music </p>
<%= simple_form_for [@user.playlist, @song] do |f| %>
<%= f.file_field :audio %>
<%= f.button :submit %>
<% end %>
</div>

<div id="user-video-box">
  <p class="p-details-title"> Add videos </p>
<%= simple_form_for @video do |f| %>
<%= f.input :youtubeurl %>
<%= f.button :submit %>
<% end %>
</div>

正如我所说,视频(这是一个 youtube url 字符串)创建和保存没有问题。歌曲的形式完全相同,基本上似乎只是更新用户registration。歌曲信息显示在服务器日志中,但没有 playlist_id 存在,也没有保存任何内容。

歌曲控制器:

def new
      if user_signed_in?
      @song = Song.new
      if current_user.playlist.songs.count >= 5
        redirect_to user_path(current_user)
        flash[:danger] = "You can only upload 5 songs."
      end
      else
     redirect_to(root_url)
     flash[:danger] = "You must sign in to upload songs"
   end
  end

  def create
    @song = current_user.playlist.songs.new song_params
    @song.playlist_id = @playlist.id
    if @song.save
        respond_to do |format|
          format.html {redirect_to user_path(current_user)}
          format.js
        end
    else
      render 'new'
    end
  end

播放列表.rb

class Playlist < ActiveRecord::Base
  belongs_to :user
  has_many :songs, :dependent => :destroy
  accepts_nested_attributes_for :songs
end

歌曲.rb

class Song < ActiveRecord::Base
  belongs_to :user
  belongs_to :playlist
  has_attached_file :audio
  validates_attachment_presence :audio
  validates_attachment_content_type :audio, :content_type => ['audio/mp3','audio/mpeg']
end

【问题讨论】:

    标签: ruby-on-rails devise simple-form nested-resources


    【解决方案1】:

    除非您通过accepts_nested_attributes_for 传递songs/playlists,否则您不应该使用registrations#edit。我将在下面详细说明实现您想要的两种方法:


    嵌套属性

    #app/models/user.rb
    class User < ActiveRecord::Base
      has_many :videos
    
      has_many :playlists
      has_many :songs, through: :playlists
    
      accepts_nested_attributes_for :videos
    end
    
    #app/models/playlist.rb
    class PlayList < ActiveRecord::Base
      belongs_to :user
      has_and_belongs_to_many :songs
    end
    
    #app/models/song.rb
    class Song < ActiveRecord::Base
      has_and_belongs_to_many :playlists
    end
    

    重要的是要正确使用它,您可以直接编辑@user 对象,通过fields_for 助手传递嵌套属性:

    #config/routes.rb
    devise_for :users, controllers: { registrations: "users/registrations", sessions: "users/sessions" }
    
    #app/controllers/users/registrations_controller.rb
    class Users::RegistrationsController < ApplicationController
      before_action :authenticate_user!, only: [:edit, :update]
    
      def edit
        @user = current_user
        @user.playlists.build.build_song
        @user.videos.build
      end
    
      def update
        @user = current_user.update user_params
      end
    
      private
    
      def user_params
        params.require(:user).permit(:user, :attributes, videos_attributes: [:youtubeurl], playlists_attributes: [song_ids: [], song_attributes: [:title, :artist, :etc]])
      end
    end
    

    这将允许您使用:

    #app/views/users/registrations/edit.html.erb
    <%= form_for @user do |f| %>
      <%= f.fields_for :videos do |v| %>
        <%= v.text_field :youtubeurl %>
      <% end %>
      <%= f.fields_for :playlists do |p| %>
        <%= p.collection_select :song_ids, Song.all, :id, :name %>
        <%= p.fields_for :song do |s| %>
          <%= f.text_field :title %>
        <% end %>
      <% end %> 
      <%= f.submit %>
    <% end %>
    

    这将为您提供一个单个表单,您可以从中为@user 创建videosplaylistssongs


    分开

    另一种选择是单独创建对象。

    没有技术上的理由比nested attributes更喜欢这种方式;你会这样做以确保你有正确的路线等。

    请注意,您需要记住 routes != 模型结构。你可以有任何你想要的路线,只要它们为你的模型定义了一个好的模式:

    # config/routes.rb
    authenticated :user do #-> user has to be logged in
      resources :videos, :playlists, :songs #-> url.com/videos/new
    end
    
    # app/controllers/videos_controller.rb
    class VideosController < ApplicationController
      def new
        @video = current_user.videos.new
      end
    
      def create
        @video = current_user.videos.new video_params
        @video.save
      end
    
      private
    
      def video_params
        params.require(:video).permit(:youtubeurl)
      end
    end
    
    # app/views/videos/new.html.erb
    <%= form_for @video do |f| %>
      <%= f.text_field :youtubeurl %>
      <%= f.submit %>
    <% end %>
    

    以上内容需要VideosControllerPlaylistsSongs 重复

    【讨论】:

    • 感谢您如此深入的回答。我尝试了各种形式并遇到了许多错误。目前,我已经摆脱了播放列表和带有歌曲的嵌套资源。用户现在拥有视频和歌曲。当表单触发视频控制器时,我可以从注册编辑页面成功创建新视频。当我尝试提交上传歌曲表格时,歌曲控制器没有被解雇,只是注册控制器(我不明白为什么)。对于我的设置,我认为我真的不需要嵌套资源,只需要能够在其他控制器中使用表单即可。
    • 最后我放弃了。我无法以这种方式创作歌曲。视频很好,我找不到两个模型之间的任何区别,所以我不明白为什么它不起作用。对于歌曲,我刚刚在注册编辑视图中呈现了一个部分表单,它可以按需要工作。
    • 没有。你绝不能阻止它。你甚至没有尝试过。你现在在吗?让我们开始聊天并完成它
    • 让我建个聊天室,我会把链接贴在这里
    猜你喜欢
    • 2011-07-13
    • 1970-01-01
    • 2016-03-21
    • 2016-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-08
    相关资源
    最近更新 更多