Redirection with parameters between controllers

855 views
Skip to first unread message

Carlos Paparoni

unread,
Apr 9, 2015, 10:27:34 AM4/9/15
to phoeni...@googlegroups.com
Hi all,

I'm learning more about Phoenix and have done an example app here: http://github.com/kenshin23/processor_phoenix (latest code in 'develop' branch) in which I upload a CSV file to be processed using ex_csv. I took some ideas off of this tutorial and got the upload to work (albeit with some things to work out), and I'm now attempting to get the file processed through my controller.

The main idea I have so far is this:
  • Call the create/2 action
    Upload the file, update the saved record with the file's data
  • (if file is a valid CSV file)
    Redirect to the step1/2 action (notice this and the following redirects)
    Show the user part of the contents of the file, to let him/her choose how to process it (select/assign headers to columns, etc)
  • (if user selected options are valid)
    Redirect to the step2/2 action
    Actually process the file with previously-selected options.
  • Redirect to the results/2 action
    Self-explanatory
I read about someone attempting to use "internal" redirection (here: https://groups.google.com/forum/#!topic/phoenix-talk/5ib9UX0OSeU) which kind of sounds what I'm looking for. I think the suggestion there was to use plugs, but I'm not familiar with their use cases. Would this be a proper option for what I want to do?

Actually, is my idea the right way to go in this case? What I'm thinking of is an installation-wizard style app, so the actions mimic that behavior.

Thanks in advance for any help or advice. I'm liking Phoenix so far, but as you can see, I still have a long way to go.

Chris McCord

unread,
Apr 9, 2015, 10:49:46 AM4/9/15
to phoeni...@googlegroups.com
Welcome Carlos,

It sounds like a normal redirect is what you want here. Is there something about our `redirect/2` helper that isn’t working for your use-case?

--
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/57e49fd0-3ac1-426e-966c-7986d6079e80%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Carlos Paparoni

unread,
Apr 9, 2015, 4:08:35 PM4/9/15
to phoeni...@googlegroups.com
Hi Chris, thanks for your reply.

Well, apparently it should work correctly, but the console gives me this (the template itself shows with the correct values, however):

[error] #PID<0.279.0> running Processor.Endpoint terminated
Server: localhost:4000 (http)
Request: POST /documents
** (exit) an exception was raised:
    ** (Phoenix.Template.UndefinedError) Could not render "create.html" for Processor.DocumentView, please define a clause for render/2 or define a template at "web/templates/document". The following templates were compiled:

* edit.html
* form.html
* index.html
* new.html
* process.html
* show.html

        (processor) web/views/document_view.ex:2: Processor.DocumentView.template_not_found/2
        (phoenix) lib/phoenix/view.ex:225: Phoenix.View.render_within/3
        (phoenix) lib/phoenix/view.ex:243: Phoenix.View.render_to_iodata/3
        (phoenix) lib/phoenix/controller.ex:460: Phoenix.Controller.render/4
        (processor) web/controllers/document_controller.ex:1: Processor.DocumentController.phoenix_controller_pipeline/2
        (processor) lib/phoenix/router.ex:300: Processor.Router.dispatch/2
        (processor) lib/phoenix/router.ex:2: Processor.Router.call/2
        (processor) lib/processor/endpoint.ex:1: Processor.Endpoint.phoenix_endpoint_pipeline/2
[info] Processing by Processor.DocumentController.process/2
  Parameters: %{"filename" => "0052_201504091953.csv", "format" => "html", "id" => "52"}
  Pipelines: [:browser]
[info] Sent 200 in 20ms
[error] #PID<0.281.0> running Processor.Endpoint terminated
Server: localhost:4000 (http)
Request: GET /documents/52/process/0052_201504091953.csv
** (exit) an exception was raised:
    ** (Plug.Conn.AlreadySentError) the response was already sent
        (plug) lib/plug/conn.ex:458: Plug.Conn.put_resp_header/3
        (phoenix) lib/phoenix/controller.ex:546: Phoenix.Controller.send_resp/4
        (processor) web/controllers/document_controller.ex:1: Processor.DocumentController.phoenix_controller_pipeline/2
        (processor) lib/phoenix/router.ex:300: Processor.Router.dispatch/2
        (processor) lib/phoenix/router.ex:2: Processor.Router.call/2
        (processor) lib/processor/endpoint.ex:1: Processor.Endpoint.phoenix_endpoint_pipeline/2
        (processor) lib/plug/debugger.ex:90: Processor.Endpoint."call (overridable 3)"/2
        (processor) lib/phoenix/endpoint/error_handler.ex:33: Processor.Endpoint.call/2


The relevant parts of the controller and router look like this:

# web/controllers/document_controller.ex
  def new(conn, _params) do
    changeset = Document.changeset(%Document{})
    render conn, "new.html", changeset: changeset
  end

  def create(conn, %{"document" => document_params}) do
    changeset = Document.changeset(%Document{}, document_params)

    if changeset.valid? do
      temp_doc = Repo.insert(changeset)
      # Validate the uploaded file and update model with file values:
      saved = upload_file_attachment(temp_doc, changeset.params, "upload_file")

      conn
     #|> put_flash(:info, "Document created succesfully.")
     #|> redirect(to: document_path(conn, :index))
     # Question: are the following 'assign's actually necessary? Seems like they aren't.
      |> assign(:id, saved.id)
      |> assign(:filename, saved.file_name)
      |> redirect(to: "/documents/#{saved.id}/process/#{saved.file_name}")
    else
      render conn, "new.html", changeset: changeset
    end
  end

  def process(conn, %{"id" => id, "filename" => filename}) do
    # TODO: Actually process the file here.
    # Just sending back the id and filename to the template to show that it's working. 
    render conn, "process.html", id: id, filename: filename
  end

# web/router.ex
# (...)
  scope "/", Processor do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
    resources "/documents", DocumentController
    get "/documents/:id/process/:filename", DocumentController, :process, as: :process # id is needed for the file's path, filename is for actually opening the file
  end


Apparently the request tries to load a "create.html" template, which doesn't exist, but it shouldn't anyway.

I'm gonna keep trying to sort this out the best I can, but any advice is highly welcome.

Chris McCord

unread,
Apr 9, 2015, 4:32:27 PM4/9/15
to phoeni...@googlegroups.com
Can you gist your entire controller and router? Or is this code on GH somewhere for me to take a look?

Carlos Paparoni

unread,
Apr 9, 2015, 5:15:55 PM4/9/15
to phoeni...@googlegroups.com
Yes, the code's on GH, here: https://github.com/kenshin23/processor_phoenix/tree/feature/process_csv_file (this is the most up-to-date feature branch)

Chris McCord

unread,
Apr 10, 2015, 2:07:36 PM4/10/15
to phoeni...@googlegroups.com
Hey Carlos, your problem is you are plugging render after action, which gets called aways. So you need to either not plug render on create, or `halt(conn)` in your create action to prevent downstream plugs from being invoked. Glancing at your controller, you already call `render`explicitly in every action, so I would just remove `plug :render …` and everything should be set.

Chris

Carlos Paparoni

unread,
Apr 10, 2015, 2:33:10 PM4/10/15
to phoeni...@googlegroups.com
Awesome, that was it! I commented out the 'plug render' part of the controller and the error went away. Thanks!

One thing down, infinity left to learn, haha.
Reply all
Reply to author
Forward
0 new messages