Rails Rendering Action in Different Controller
So I have a controller called Music with one action which is index. On the music/index.html
page I list out a bunch of Songs (via a Song model) and at the bottom I have a for to create a new Song.
Song has validations which I have tested and work 开发者_开发问答just fine. When the new Song saves in controller Songs action create I redirect_to => 'music_index_path'
so the person can see the new song in the list. However when the Song does not save (does not pass validations) then I cannot use redirect_to
since the form error_messages do not carry over. I need to use render
but cannot say render :controller => 'music', :action => 'index
.
My goal is to be able to show the error messages for the Song form ON the music/index.html page.
How should I go about this. I am open to other ideas (like changing up controllers) as well.
Thanks!
It sounds to me like Music should be a part of Song, or the other way around. You can always use routes to disguise it as one or the other to the user. song/index sounds to me like it should display all songs, which is all music does anyway.
My first thought is that we need to rethink this process. Assuming you're using RESTful controllers, it's unclear to me why you would need a Music controller and a Song controller... how are those resources different? The next relevant question would be, why is it not sufficient to show errors via Song#create ? I mean, they couldn't get it right when it was just a form, is the distraction of additional content likely to help? :)
With that said, here is a possible solution. (Given that you didn't paste your code, I'm making a lot of assumptions here.)
<hack>
first, extract the form parts from songs/new to songs/_form, then from the music/index view, render :partial => songs/_form, and in the songs controller, render :action => '../music/index' (this is called a hackity-hack.) Because it's a hack, you will almost certainly need to go into music#index and add @song = Song.new
</hack>
If you start running on edge, the ability to pass a flash through a redirect was just added...but that doesn't really get you there.
The simplest solution though, is that you need to render index, but set up all of the variables that are needed for that page. If you factor that out into a separate module or method, you can call it from both the index action and the save failure.
def index
setup_for_index
end
def create
@song = Song.new(params[:song])
@song.save
#...
#on failure
setup_for_index
render :controller => "music", :action => "index"
end
def setup_for_index
@songs = Song.all
#etc
end
The other thing you could do is use form_remote_for
and have the song form just update the div on failure. Then use an RJS template return type reload the whole song list on success.
While I want to reiterate what others have stated about your resource architecture deserving a second look, you can certainly render views for other resources using the :template
option:
render template: 'music/index'
Why not a simple if request.post? conditional in the index action's view rather than redirecting to another page?
You can also try using flash[:song_save_error]
to pass the error conditions back to your Music controller.
http://api.rubyonrails.org/classes/ActionController/Flash.html
You could try render :file => ...
精彩评论