For certain models, I wish to provide functionality that allows a user to create a new record with 开发者_开发百科default attributes based on copy of an existing record.
I'm wondering what would be the correct restful route for this.
My initial thinking is that it could be a parameter to the new
action. I.e. to borrow from the the Rails Guides examples, instead of just:
GET : /photos/new
Also allow:
GET : /photos/new/:id
...where :id
is the id of the record to use as a template. The response would be a new/edit form, same as with a plain old new
but the values would be pre-filled with data from the existing record. The parameter (or absense of it) could be easily handled by the new
controller method.
The alternative seems to be to create a new controller method, for example copy
which would also accept an id of an existing record and response with the new form as above. This seems a little 'incorrect' to me, as the record is not actually being copied until the user saves the new record (after probably editig it somewhat).
TIA...
UPDATE: my question is not "how do I do this in rails?", it's "is it RESTful?"
my question is not "how do I do this in rails?", it's "is it RESTful?"
No, it isn't. For that matter, neither is GET /photos/new
. Rails seems to be hopelessly mired in the past, where it was considered haute programme for a GET on a URI to return an HTML form which would then POST x-www-form-urlencoded data back to that same URI. The opacity of that POST forces them to invent new verbs-as-URI's like /photos/new
, when you could be using PUT instead, or at least POST with the same media type.
The simplest way to make a copy of an HTTP resource RESTfully is:
GET /photos/{id}/ -> [representation of a photo resource]
...make modifications to that representation as desired...
POST /photos/ <- [modified representation]
If you're implementing this for browsers, you should be able to perform those actions via Ajax quite easily, using an HTML page sitting perhaps at /photos/manager.html/
to drive the interaction with the user.
You can try to use nested resources. I'm not exactly sure about structure of you application, but in general using nested photos will look somehow like this:
routes.rb
resources :photos do
resources :photos
end
photos_controller.rb
before_filter :find_parent_photo, :only => [:new, :create]
def create
@photo = Photo.new params[:photo]
if @parent_photo.present?
# fill some @photo fields from @parent_photo
end
@photo.save
respond_with @photo
end
def find_parent_photo
@parent_photo = Photo.find(params[:photo_id]) if params[:photo_id].present?
end
new.html.haml
= form_for [@parent_photo, @photo] do |f|
-# your form code
previously when you wanted to add a link to photo creation you wrote something like that
= link_to "new photo", [:new, :photo]
now if you want to add a link to photo creation based on foto @photo1
= link_to "new photo based on other one", [:new, @photo1, :photo]
You should be able to match
a route like so:
match 'photos/new/:photo_id' => 'photos#new
or you could just pass a :photo_id
parameter in the url and handle it in the controller:
'/photos/new?photo_id=17'
Example using helper method: new_photo_path(:photo_id => 17)
Edit: I don't know if this conforms to REST
It may be over the top, but you could do something like this:
class PhotoCopiesController < ApplicationController
def new
@photo = Photo.find(params[:photo_id]).dup
end
def create
end
end
and
resources :photo_copies, :only => [:new, :create]
and
= link_to 'Copy', photo_copy_path(:photo_id => @photo.id)
精彩评论