Вопрос

I have a deeply nested resource. Currently everything works fine, except when I crate a SONG. For some reason it does not store the ARTIST_ID in the database (shows up as NIL). Can someone please help me, I am a newb.

The first nested stores the ARTIST_ID in the ALBUMS table...

ROUTES.RB

resources :artists do
  resources :albums do
    resources :songs
  end
end

SONGS_CONTROLLER

class SongsController < ApplicationController

  respond_to :html, :js

  def index
    @artist = Artist.find(params[:artist_id])
    @album = Album.find(params[:album_id])
    @songs = @album.songs.all
  end

  def create
    @artist = Artist.find(params[:artist_id])
    @album = Album.find(params[:album_id])
    @song = @album.songs.create(params[:song])
      if @song.save
        redirect_to artist_album_songs_url
        flash[:success] = "Song Created."
      else
        render 'new'
      end
  end

  def new
    @artist = Artist.find(params[:artist_id])
    @album = Album.find(params[:album_id])
    @song = Song.new
  end

end

MODELS

class Artist < ActiveRecord::Base
  attr_accessible :name

  has_many :albums
  has_many :songs

end

class Album < ActiveRecord::Base
  attr_accessible :name, :artist_id

  belongs_to :artist
  has_many :songs

end

class Song < ActiveRecord::Base
  attr_accessible :name, :album_id, :artist_id

  belongs_to :albums

end

VIEW (CREATE, FOR SONGS)

<div class="container-fluid">
  <div class="row-fluid">

    <%= form_for ([@artist,@album, @song]), :html => { :multipart => true } do |f| %>
      <%= render 'shared/error_messages', object: f.object %>

      <%= f.text_field :name, placeholder: "name", :class => "input-xlarge"%>

      <%= f.submit "Create Song", class: "btn btn-primary"%>

    <% end %>

  </div>

</div>
Это было полезно?

Решение

IT looks like you're not setting the artist_id on the song anywhere. You are doing it right though - with a album_id and artist_id, you have to pick one of those as the parent. It's as though you are caching the artist_id on the song.

I think I would keep things they way you are doing it but add this to the model.

class Song < ActiveRecord::Base

  before_save :ensure_artist_id


  def ensure_artist_id
    self.artist_id = self.album.artist_id
  end

end

The other option is to set it in the controller explicitly

  def create
    @artist = Artist.find(params[:artist_id])
    @album = Album.find(params[:album_id])
    @song = @album.songs.create(params[:song].merge(:artist_id => @artist.id)
      if @song.save
        redirect_to artist_album_songs_url
        flash[:success] = "Song Created."
      else
        render 'new'
      end
  end

But that doesn't feel as clean and may be repeated in other controller methods. It's nicer to have it in the model.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top