Passing id/object from one page/context to another in Phoenix 1.4 - phoenix-framework

I have an Events page that is a list and I want a user to click on a specific Event to create a Request to be invited. I want the Request to be tied to that Event and want Event data (name, location, etc) to show on the new request form page.
Events are one type of "object" and the Requests are another. One Event can have many Requests, but not the other way (so one-to-many). I can do a has_many/belongs_to relationship if that makes it better, or I can simply put an event_id in the Requests - I don't have a preference. This is a Phoenix 1.4 project, nothing special or custom, backed by a PostgreSQL DB.
What I can’t figure out is how to pass the Event, or the event_id, to the New Request form. Most everything in the Phoenix framework is really great, but I can’t figure out the right way to do this one simple thing.
What I have right now is more or less based on the basic guides:
project/lib/project_web/templates/tms/event/index.html.eex (Events list)
<table><tbody><tr><td><%= link event.title, to: Routes.tms_request_path(#conn, :new) %></td></tr></tbody></table>
This goes to
lib/project_web/controllers/request_controller.ex (controller)
def new(conn, _params) do
changeset = TMS.change_request(%Request{})
render(conn, “new.html”, changeset: changeset)
end
This goes to
lib/project/tms.ex (context)
def change_request(%Request{} = request) do
Request.changeset(request, %{})
end
Which goes to
lib/project/tms/request.ex (schema)
def changeset(request, attrs) do
request
|> cast(attrs, [:name, :event_id, :email, :request_count]
|> validate_required([:name, :event_id, :email, :request_count]
lib/project_web/tms/request/new.html is a form with boxes for the attributes of the request
Everything with this works fine right now in that I can click on the link in the Events list and be taken to the New Requests form page and can save the request. Obviously, though there is no ID or association established this way.
Obviously I want to do this the Elixir way and not hack something together. I've tried several different ways to pass event_id around but none of them seem to work, so I know I'm missing something but at this point, I can't figure out what that is.

The event id can be passed through params as:
Routes.request_path(#conn, :new, event_id: event.id) # not tms_request_path
And receive in lib/project_web/controllers/request_controller.ex as event_id parameter in new function:
def new(conn %{"event_id" => event_id}) do
# the even_id can be passed directly to new form
render(conn, “new.html”, event_id: event_id)
end
Then you can acquire event_id in new form as #event_id parameter

Related

Odoo 8/9/10 API, how to create an invoice from a sale order via XMLRPC

I'm developing a ruby application which sends some commands to Odoo via XMLRCP API.
I've been able to create a sale order in this whay
def execute_odoo_command(odoo_model, odoo_command, values)
#models.execute_kw(ODOO_DB, #uid, ODOO_PASSWORD, odoo_model, odoo_command, values)
end
def create_order_sale
order_reference = "SO #{#reference_code}_#{#customer_odoo_id}"
values = {
currency_id: 1,
date_order: Date.today.to_s,
name: order_reference,
payment_term: 1,
partner_id: #customer_odoo_id
}
order_id = execute_odoo_command('sale.order', 'create', [values])
create_sale_order_lines(order_id)
execute_odoo_command('sale.order', 'action_confirm', [order_id])
end
Now, I would launch the invoice creation. I have found a way to do it like this
execute_odoo_command('account.invoice', 'create', [invoice_values(order_reference)])
But, even if the invoice is created, the sale order is stil "open" and I can create another invoice from the Odoo interface clicking on "Create Invoice" button (which is obviously wrong). Is there any way to simulate that action via API?
The debug mode does not show any method in the tooltip.
Any suggestion is appreciated, thank you!
For future googlers. The solution is that I'm using an old API version. the right command call is this one
def create_invoice_from_sale_order(sale_order_id)
sale_order_to_invoice_data = [sale_order_id, {context: {active_ids: sale_order_id}}]
#odoo_rpc_client.execute_odoo_command('sale.order', 'action_invoice_create', sale_order_to_invoice_data)
end

How to add nested form field into current form dynamically?

I have a many to many relationship between Users and Chatgroups. Intuitively, Users can have many Chatgroups and each Chatgroup can have many users.
I've implemented this with a join table called UserChatGroup.
In my Chatgroup controller, when routed to the new function, I can hardcode the number of members in a chatgroup by specifying userChatGroups:[%UserChatGroup{},%UserChatGroup{}] etc, where the hardcoded number is the size of this array.
For example, my controller for a new chat group hardcodes 1 user:
def new(conn, _params) do
changeset = ChatGroup.changeset(%ChatGroup{userChatGroups: [%UserChatGroup{}]})
render(conn, "new.html", changeset: changeset)
end
and in my template for new, it references a form. The relevent section of the form is below:
<%= inputs_for f, :userChatGroups, fn i -> %>
<div class="form-group">
<%= label i, :user_id, "User Id", class: "control-label" %>
<%= number_input i, :user_id, class: "form-control" %>
</div>
<% end %>
However I'd like to remove this hardcoded number of members in the chat group. Instead I'd like the user to be able to add members dynamically.
I'm having trouble with this however. The rails way of doing this is to call a function that accesses the form object and updates it. Then insert input fields with javascript. On submitting, the new input fields would be fields for the new form object.
However I can't figure out how to do this with the Phoenix Framework.
My first question:
How do I define functions in my view.html.eex so that they can be called on click and not simply rendered immediately? Seems like when I try using <%= functionFromMyView %> the function is rendered on initial load of my page. I want to call this function when I click an 'add' button so I need to figure out how to call this function only on click. Is that possible?
Question 2, more specific to my use case:
How do I add %UserChatGroup{} dynamically to my form?
I'm assuming that once I can figure out how to call a function from my view on a click, then I can use that function to insert a %UserChatGroup{} to my form and then using javascript, insert an input field that connects to the newly inserted nested UserChatGroup field.
Any guidance would be greatly appreciated.
I wasn't able to add a %UserChatGroup{} to my form.
I believe this is because the web is HTML, CSS, and JS, whereas the above was Elixir.
Therefore I assume my solution must be javascript.
I examined the html on the page which told me the %UserChatGroup{} input field had a name name="chat_group[userChatGroups][0][user_id]"
chat_group is the name of the model I am creating,
userChatGroups is the array I created to handle the members of the chat group,
[0] is the index of the input array and can go as big as you want a group to be
user_id is the field in my join table.
The index is the only value you need to change.
With javascript, I inserted input fields within my form, with a name="chat_group[userChatGroups][--indexnumber--][user_id]" and when submitting, the form would naturally also submit my newly added input. (replace indexNumber)
This way can handle adding as many chat group users as I needed.

Grails chained drop down

I'm trying to implement chained drop down boxes using the tutorial here. My classes are not as straight forward as the ones in the tutorial though.
I want to chain the drop down boxes for the create.gsp view in the Load class. Each load belongs to an account from the Account class, and each account belongs to a user from the User class, and each user has several cargo destinations from the Address class.
My goal is to have the cargo destination field up date based on which account is selected.
I am having trouble understanding the AJAX function in the tutorial (step 3), and how it relates to the Grails function (step 4).
Here is the AJAX code:
function respondToSelect(event)
{
new Ajax.Updater("memberSelect",
"/chainedSelect/family/updateSelect",
{method:'get', parameters: {selectedValue : $F("familySelect")} }
);
}
Here is the Grails method:
def updateSelect = {
def familySelected = Family.find("from Family as family where family.surname=:surname", [surname:params.selectedValue])
render (template:"selectMember", model : ['familySelected' : familySelected])
}
If someone could just explain what the third parameter of the AJAX function is doing I think I can figure the Grails part out.
{method:'get', parameters: {selectedValue : $F("account")}}
If someone could just explain what the third parameter of the AJAX
function is doing
The third argument is an object of parameters that get passed to the Updater that tell it how to make the HTTP request to the server.
Make the request an HTTP GET request:
method:'get'
Pass the following named query parameters:
{selectedValue: $F("account")}
$F is a prototype shortcut to retrieve the value of an element. In this case, it's getting the selected value of the DOM element with id account.
This ultimately results in something like the following request:
GET /chainedSelect/family/updateSelect?selectedValue=someValue
Where "someValue" is the currently-selected item in the "account" select list.

Form helpers in case of Single Table Inheritance

I have to implemene Single Table Inheritance for a class Person who can be of type Teacher, Student,Outsider.
class Person < ActiveRecord::Base
end
class Teacher < Person
end
class Student < Person
end
class Outsider < Person
end
What changes do I need to make in the routes and the forms while register a new user. I have a column(string) "type" in the people table which can be implemented as a dropdown in the form to register a new user. Is there anything else that I need to do in the form so the user is registered as a particular type of Person? Do I need to make any changes in the routes too?
Since you use one form to create all types of Persons, then you should stick with one Controller as well so you don't need to add any additional routes.
The type attribute is not really something you should assign manually to an instance, it should be set automatically by choosing which type of model to create.
I don't know how it looks in your controller and views, but you can extract the type of model to create like this:
class_type = params[:type].constantize
#person = class_type.new
On the other hand, if the type attribute is nested in a form_for in your view, then the type attribute is probably send to the controller like params[:person][:type] in which case it should be removed from the :person hash before it is used to create the new instance. Perhaps something like this:
class_type = params[:person].delete(:type).constantize
#person = class_type.new(params[:person])
Except adding a dropdown list of type selection in the form, there's nothing more to do. You can create a user in the normal way, like:
#user = Person.new params[:user]
But the type attribute could not be mass assigned, so you have to assign it separately.
#user.type = sanitize_user_type params[:user][:type]
The method sanitize_user_type is used to validate user input value.
The route for creating new user doesn't need to change. Whether other routes need to change or not depend on your requirement. Actually you can add the routes for Teacher, Student, Outsider and relative controllers, so that you can build restful urls.

Grails: can remoteField update multiple fields?

Assume i have a book entity with an isbn field.
When entered a isbn number, i want 2 fields to be updated: title and author.
My controller looks like this:
def ajaxGetBook = {
def book = Book.findByIsbn(params.isbn)
if(book==null) book = new Book()
render book as JSON
}
So my call works, and i get a full JSON Book.
Now i would like to update 2 texfields by the update attribute
<g:remoteField action="ajaxGetBook" update="title" name="isbn" value="${bookInstance?.book?.isbn}" paramName="isbn"/>
Now the title field gets updated with the full book object, so that doesn't work.
Is it possible to update field title with only the JSON book.title?
Is it possible to update more fields at once?
I could render book.title as JSON but that works for only one field.
Thank you
Well, the g:remoteField tag is explicitly for one field, so you can't use it to update more than one. So, you're left with 2 easy choices:
Use 2 g:remoteField calls... this isn't a bad option, as they would happen in near parallel, as they are Async calls.
Roll your own Ajax. use g:remoteFunction instead, and have the JS function that you place in the "success" attribute take your book, and update the appropriate HTML fields.

Resources