Using mix phoenix.gen.resource + Nested Resources = compilation error. Help please?

1,035 views
Skip to first unread message

Carlos Paparoni

unread,
Apr 2, 2015, 11:11:54 AM4/2/15
to phoeni...@googlegroups.com
Hi all, I'm new to Phoenix and Elixir in general.

I'm working on a new project and I ran into an issue using the resource generator. Suppose I have three models, User, Document, and Record. A User can have many Documents, and a Document can have many Records, so I started by generating the resources one by one with mix phoenix.gen.resource, and then adding an extra migration to add the foreign keys to the database.

However, I saw here under Nested Resources that you can represent one-to-many relationships by nesting routes, which I did (after running mix ecto.migrate.) But now mix compile returns the following:

$ mix compile
Compiled lib/my_app.ex
Compiled web/router.ex
Compiled web/views/user_view.ex
Compiled lib/my_app/endpoint.ex
Compiled web/views/page_view.ex


== Compilation error on file web/views/record_view.ex ==
** (CompileError) web/templates/record/edit.html.eex:4: function record_path/3 undefined
   
(stdlib) lists.erl:1336: :lists.foreach/2
   
(stdlib) erl_eval.erl:657: :erl_eval.do_apply/6

which is supposed to be the error I should get if I didn't run the migration first (but I did.) I take it that the resource generator doesn't support resource relationships yet, which is ok, but what should I edit in order for my changes to work?

Thanks in advance for any help or advice.

Louis Pilfold

unread,
Apr 2, 2015, 11:42:14 AM4/2/15
to phoeni...@googlegroups.com
Hey!

So I've not messed about with Phoenix's nested resources just yet, but
I'll go out on a limb and guess that they work in a similar fashion to
Rails' nested resources. (There's a good chance I'm wrong though!)

Previously the only information you needed to generate a path to a
Record via a helper method (`record_path/3`) was the record id. Now
that it's nested within a Document you need the id for the Record, and
also the id for the parent Document.


In Rails land you'd go from this...

record_path(@record)

...to this...

document_record_path(@document, @record)

...when you nest the Record resource within the Document resource.

Perhaps you now have a `document_record_path/4`?

Cheers,
Louis
> --
> You received this message because you are subscribed to the Google Groups
> "phoenix-talk" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to phoenix-talk...@googlegroups.com.
> To post to this group, send email to phoeni...@googlegroups.com.
> Visit this group at http://groups.google.com/group/phoenix-talk.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/phoenix-talk/a65acf87-08d9-49f3-9e27-ee113d237b65%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Carlos Paparoni

unread,
Apr 2, 2015, 2:38:36 PM4/2/15
to phoeni...@googlegroups.com, lo...@lpil.uk
Hi again, thank you very much for the quick reply!

I managed to get the code to compile (by fully qualifying the *_path functions -- don't know if that's correct, but it worked, at least to compile) and doing mix phoenix,routes returns this:

$ mix phoenix.routes
          web_socket_path  GET    
/phoenix                                                 Phoenix.Transports.WebSocket.upgrade/2
          web_socket_path  POST    
/phoenix                                                 Phoenix.Transports.WebSocket.upgrade/2
         long_poller_path  GET    
/phoenix/poll                                            Phoenix.Transports.LongPoller.poll/2
         long_poller_path  POST    
/phoenix/poll                                            Phoenix.Transports.LongPoller.publish/2
                page_path  GET    
/                                                        MyApp.PageController.index/2
                user_path  GET    
/users                                                   MyApp.UserController.index/2
                user_path  GET    
/users/:id/edit                                          MyApp.UserController.edit/2
                user_path  GET    
/users/new                                               MyApp.UserController.new/2
                user_path  GET    
/users/:id                                               MyApp.UserController.show/2
                user_path  POST    
/users                                                   MyApp.UserController.create/2
                user_path  PATCH  
/users/:id                                               MyApp.UserController.update/2
                           PUT    
/users/:id                                               MyApp.UserController.update/2
                user_path  DELETE  
/users/:id                                               MyApp.UserController.delete/2
       user_document_path  GET     /
users/:user_id/documents                                MyApp.DocumentController.index/2
       user_document_path  GET    
/users/:user_id/documents/:id/edit                       MyApp.DocumentController.edit/2
       user_document_path  GET    
/users/:user_id/documents/new                            MyApp.DocumentController.new/2
       user_document_path  GET    
/users/:user_id/documents/:id                            MyApp.DocumentController.show/2
       user_document_path  POST    
/users/:user_id/documents                                MyApp.DocumentController.create/2
       user_document_path  PATCH  
/users/:user_id/documents/:id                            MyApp.DocumentController.update/2
                           PUT    
/users/:user_id/documents/:id                            MyApp.DocumentController.update/2
       user_document_path  DELETE  
/users/:user_id/documents/:id                            MyApp.DocumentController.delete/2
user_document_record_path  GET     /
users/:user_id/documents/:document_id/records           MyApp.RecordController.index/2
user_document_record_path  GET    
/users/:user_id/documents/:document_id/records/:id/edit  MyApp.RecordController.edit/2
user_document_record_path  GET    
/users/:user_id/documents/:document_id/records/new       MyApp.RecordController.new/2
user_document_record_path  GET    
/users/:user_id/documents/:document_id/records/:id       MyApp.RecordController.show/2
user_document_record_path  POST    
/users/:user_id/documents/:document_id/records           MyApp.RecordController.create/2
user_document_record_path  PATCH  
/users/:user_id/documents/:document_id/records/:id       MyApp.RecordController.update/2
                           PUT    
/users/:user_id/documents/:document_id/records/:id       MyApp.RecordController.update/2
user_document_record_path  DELETE  
/users/:user_id/documents/:document_id/records/:id       MyApp.RecordController.delete/2

so you're onto something there. Now, I'm still struggling a little bit with Elixir's syntax (coming from pure Erlang -- and I'm still a beginner there as well), so I don't know yet what parameters I should pass to the relevant *_path functions, or how, but at least you managed to point me in the right direction.

I'll keep testing to see what I can find. Thanks again!

Chris McCord

unread,
Apr 2, 2015, 2:44:02 PM4/2/15
to phoeni...@googlegroups.com
The generators create the html template without nesting contexts. So when you added the nested `resources “/records”`, you also need to go and update your path helpers to use the `document_record_path` helpers. Then all should be well. Feel free to hop on elixir-lang irc if you have routing questions.


Carlos Paparoni

unread,
Apr 3, 2015, 5:21:42 PM4/3/15
to phoeni...@googlegroups.com
Hi Chris,

Thanks for your reply. I've been playing with the generated resources and found (?) that I have to basically edit all of the methods inside the controller and the generated templates as well to add the extra User and Document relationships.

I assume that all my index/2, edit/2, etc. methods in the controllers would change to index/3, edit/3, (...) or index/4, edit/4, (...) depending on the nesting level, correct? I've been looking for examples on nested resources but haven't found a complete one, with controllers and templates to help me figure this out. If you (or anyone else) find one, or could provide one, that'd be really great.

So far, my test project is here. Please feel free to look through it and comment if you find anything wrong or that could be improved.

Thanks,

Chris McCord

unread,
Apr 3, 2015, 7:31:04 PM4/3/15
to phoeni...@googlegroups.com
Your controller action arity would remain the same, but the params would contain the parent relationships, i.e.:

def show(conn, %{“document_id” => doc_id, “id” => rec_id”}) do


In the case of having to update the templates, this is okay. The generators are just mean for quick bootstrapping, especially when starting out. I’ll take a look and drop some notes as I come across things.

Chris

Reply all
Reply to author
Forward
0 new messages