Need help passing parameters from the view to the controller with link

Hello!
I’m newer to Phoenix and fullstack development in general.

I’m wanting to create a controller action that take in two pieces of information in the view.

The business purpose is to create a type of contract between two other tables, a Wholesaler and Retailer which is stored in a Contract table. This is to allow requests to be created between organizations.

Contract
status: string
wholesaler_id
retailer_id
user_id

in my router

resources "/contracts", ContractController

I’m wanting to use the contract create action to create a request with a link. The link occurs within an iterator. I have a current user item assigned to @current_user.

<%= for retailer <- @retailer do %>

<%= link "Request Contract", to: contract_path(@conn, :create, @current_user, retailer.id) %>
<% end %>

When I click the link, I’d want a new contract instance to be created with
The retailer id populating the retail field and the current user id to be user_id. I have a field in the user that would populate the wholesaler id.

I’ve tried a few things in the controller, but I lack a basic understanding of how this works. This is the current iteration. Also let me know if I’m doing this completely wrong and there’s a much smarter way of doing this.

  def create(conn, %{"id" => id}, %{"org" => org}) do
    retailer_id = id
    wholesaler_id = org
    map = {"retailer_id" => id, "wholesaler_id" => org}
    App.create_contract(map)
  end

You can pass like that

<%= link "Request Contract", to: contract_path(@conn, :create, @current_user,  param: "test") %>

edit: It is a post request so that doesnt work

2 Likes

What have you done with Phoenix so far?

For example, it would be helpful if you are already familiar with Building Forms, Programming Phoenix ≥ 1.4 p.60. Fundamentally with HTML the create action is a result of a form being submitted.

resources "/contracts", ContractController

creates among others a POST /contracts HelloWeb.ContractController :create route which typically the form inside the page loaded with /contracts/new submits to. When that submit happens, the information inside the form is sent to the server as form data. The form data is essentially a list of key/value pairs - Phoenix turns those key/value pairs into a single Elixir Map. That map is supplied as the second (params) parameter to the create action inside the ContractController.

Given the above the simplest approach is to represent the retailers as radio buttons (the value being the retailer_id) inside a form. That way the retailer_id should appear in create’s params map value. The current user should be available in the (first) conn argument (conn.assigns.current_user) giving you the necessary information.

Don’t forget to redirect at the end to let the user know whether the “contract create” failed or succeeded.

2 Likes

So I have a familiarity of that, but what I’m trying to do is basically list out all the retailers. Then as a wholesaler user I can see a list of the wholesalers with buttons in each row that say “Request Contract.”

When I click that button, I create a new contract in the database. That table will have the retailer’s id (from the iterator), the current user’d id and then the wholesaler’s id (from a field in the user’s info).

I tried that and I got a different error stating the view was unavailable.

If I get You right, You already have the current user id, and this current user is associated with a wholesaler id.

So no need to do anything because these informations come from authentication.

Then You need to create a new contract…

You can get all the requested information with a nested route like this…

/retailers/:id/contracts/new

You will get retailer id from the route.

It’s an HTML problem. I assume that a contract can only be requested once - so processing a contract request should probably remove the button or make the row go away entirely which will require a page reload (the purpose of the redirect).

This is very close and something I would do coming from a Rails understanding. However it doesn’t seem to take. It has something to do with the link. I have a clue: when I define the link as you have here, but put the parameters in a list format, then it will render. I might tool around with that.

‘’’
<%= link “Request Contract”, to: contract_path(@conn, :create, [@create_user, courier.id]) %>
‘’’

You can use a form like that for request. Post request parameters doesnt show in url for security.

#form in view
<%= form_for @conn, contract_path(@conn, :create), [ method: :post] , fn f ->%>
  <%= hidden_input f, :retailer_id, value: retailer.id %>
     <%= submit "Request Contract", class: "btn btn-primary" %>    
 <% end%>  

#controller function
 def create(conn, %{"retailer_id" => retailer_id}) do
    map = %{....}
    App.create_contract(map)
   reditect(conn, to: "/contracts")
  end
8 Likes

This solved it! I didn’t even know you could do this! Thank you very, very much! I just need to get the user’s field for wholesaler to pass into the hidden input.