Rails ActiveRecord'稍微'复杂的协会

时间:2016-06-28 23:53:09

标签: ruby-on-rails ruby activerecord database-design ruby-on-rails-4.2

我想构建一个音乐网络应用程序的数据库,以使用以下结构。

歌曲(属性:名称,年份等(任何其他相关属性))

  • 有很多演出
  • 有很多表演者(通过演出
  • 有很多艺术家(通过表演者

效果(外键:Song_id,属性:枚举版本:[:官方,:混音,:封面])

  • 属于歌曲
  • 有很多表演者
  • 有很多艺术家(通过表演者

表演者(外键:Performance_id,Artist_id,属性:枚举角色:[:main_artist,:collaborating_artist,:featuring_artist,:versus])

  • 有一首歌曲(通过表演者
  • 属于效果
  • 属于艺术家

艺术家(属性:名称,DOB等(任何其他相关属性))

  • 有很多表演者
  • 有很多演出(通过演员
  • 有很多歌曲(通过演出

因此,在保存歌曲时,我可以填充所有其他表格,也就是通过关联,但是,到目前为止,我有以下实现:

歌曲模型:

    class Song < ActiveRecord::Base

        #Added to make the db more logical and ended up complicated
        has_many :performances
        has_many :performers, :through => :performances
        has_many :artists, :through => :performers

        accepts_nested_attributes_for :artists, allow_destroy: true
        accepts_nested_attributes_for :performers, allow_destroy: true
        accepts_nested_attributes_for :performances, allow_destroy: true

        validates :name, :presence => true, uniqueness: true
        validates :year, :presence => true
    end

表现模式:

   class Performance < ActiveRecord::Base
      enum version: [:official, :remix, :cover]

      belongs_to :song
      has_many :performers
      has_many :artists, :through => :performers
    end

表演者模特:

   class Performer < ActiveRecord::Base
      enum role: [:main_artist, :collaborating_artist, :featuring_artist, :versus]

      belongs_to :artist
      belongs_to :performance
      has_one :song, :through => :performers #this upsets the back hairs!
    end

艺术家模特:

    class Artist < ActiveRecord::Base

        #Added to make the db more logical and ended up complicated
        has_many :performers
        has_many :performances, :through => :performers
        has_many :songs, :through => :performances

        validates :name, :presence => true, uniqueness: true
    end

歌曲控制器

class SongsController < ApplicationController
    before_action :find_song, only: [:show, :edit, :update, :destroy]

    def index
     ...
    end

    def new
       @song = Song.new
       @song.performers.build
       @song.performances.build
       @genres = Genre.all #.map{|c| [ c.name, c.id ] }
       @countries = Country.all.map{|c| [ c.name, c.id ] }
    end

   def create
      @song = Song.new(song_params)
      if @song.save
        redirect_to @song, notice: 'Successfully added a song.'
      else
        render 'new'
      end
   end

   def show
      ...
   end

   def update
      if @song.update(song_params)
         redirect_to @song, notice: 'Successfully updated the song.'
      else
         render 'edit', notice: 'Unable to save the changes'
      end
   end

   def edit
      ... 
   end

   def destroy
      ...
   end

   private 

   def song_params
       params.require(:song).permit(:name, :year, artists_attributes: [ :id, :name, :DOB], performances_attributes: [:id, :version, :song_id], performers_attributes: [:id, :performance_id, :artist_id]) 

   end

   def find_song
      @song = Song.find(params[:id])
   end
end

new.html.erb

    <div class="content">
        <%= form_for @song, html: { multipart: true } do |f| %>

            <% if @song.errors.any? %>
                <div>
                    <%= @song.errors.count %>
                    Prevented this song from saving
                    <ul>
                        <% @song.errors.full_messages.each do |msg| %>
                            <li><%= msg %></li>
                        <% end %>
                    </ul>
                </div>
            <% end %>

            <div class="field">
                <%= f.label :name %><br>
                <%= f.text_field :name, class: "input-field"  %>
            </div>

            <div class="song-version">
                <div class="field">
                    <%= f.fields_for :performances do |performances_for_form| %>
                        <%= render 'performances_fields', f: performances_for_form %>
                    <% end %>
                </div>
            </div>

            <div class="performers-fields">
                <h2>Artist(s)</h2>
                <div class="field">
                    <%= f.fields_for :performers do |performers_for_form| %>
                        <%= render 'performers_fields', f: performers_for_form %>
                    <% end %>
                </div>
            </div>

            <div class"btn">
                <%= f.submit %> 
            </div>

        <% end %>
    </div>

表现部分

    <fieldset>
        <div class="field">
          <%= f.label :version %>
          <%= f.select :version, Performance.versions.keys %>
        </div>
    </fieldset>

执行者部分

    <fieldset>  
        <h2>Artists Details</h2>
        <div class="field">
            <%= f.fields_for :artists do |artists_for_form| %>
                <%= render 'artist_fields', f: artists_for_form %>
            <% end %>
        </div>
        <div class="field">
          <%= f.label :artists_role %>
          <%= f.select :role, Performer.roles.keys %>
        </div>
    </fieldset>

艺术家部分

    <fieldset>
        <div class="field">
          <%= f.label :name %>
          <%= f.text_field :name %>
        </div>
        <div class="field">
          <%= f.label :DOB %>
          <%= f.datetime_select :DOB, :ampm => true, :minute_step => 15 %>
        </div>
    </fieldset>

当我填写表单上的所有数据时,保存后,只有歌曲的属性演奏组属性会保存到数据库中,而表演者&amp;艺术家永远不会保存,连接也没有建立,我的问题是:

  • 这个结构在逻辑上是否正确?如果不是错误地做了什么。
  • new, create methods的{​​{1}}是否被错误地实施,因此无法正确保存数据?
  • 使用这种数据库结构开发此类Web应用程序可以采用哪些权利和/或最佳实践?
  • 或者是否还有其他更好或简洁的数据库结构,而不是这个?

0 个答案:

没有答案