I am new to actionmailer and can't seem to get ActionMailer to work and route properly, not sure if I'm doing it properly and most tutorials only show how to generate a generic email after a user has first created an account.
What I am trying to do is allow a user to generate an email through a form to send an email message with a link to a view to their clients to view an invoice.
My current error is due to some routing issues but the strange thing was that it's looking for an email template in my controller instead of the mailer controller is my assumption... Missing template invoices/send_invoice_email, application/send_invoice_email
Here is my form which the user would use to build the email.
<%= bootstrap_form_tag url: '/send_invoice' do |l| %>
<%= l.hidden_field :invoice, value: #quote.id %>
<div class="input-group margin-bottom-20">
<span class="input-group-addon" id="from"><i class="fa fa-envelope"> </i></span>
<%= l.text_field :from, hide_label: true, value: current_user.email %>
</div>
<div class="input-group margin-bottom-20">
<span class="input-group-addon" id="to"><i class="fa fa-user"> </i></span>
<%= l.text_field :to, hide_label: true, value: #quote.client.contacts.first.email %>
</div>
<div class="input-group margin-bottom-20">
<span class="input-group-addon" id="cc"><i class="fa fa-users"> </i></span>
<%= l.text_field :cc, hide_label: true, placeholder: "cc:" %>
</div>
<div class="input-group margin-bottom-20">
<span class="input-group-addon" id="bcc"><i class="fa fa-users"> </i></span>
<%= l.text_field :bcc, hide_label: true, placeholder: "bcc:" %>
</div>
<div class="input-group margin-bottom-20">
<span class="input-group-addon" id="subject"> <i class="fa fa-bullhorn"></i></span>
<%= l.text_field :subject, hide_label: true, placeholder: "Subject" %>
</div>
<div class="input-group margin-bottom-20">
<span class="input-group-addon" id="message"> <i class="fa fa-comment"></i></span>
<%= l.text_area :message, hide_label: true, placeholder: "Message", rows:"5" %>
</div>
<%= l.submit "Send", class:'btn-u btn-u-blue btn-block' %>
<% end %>
My controller method in my invoice controller (this is only a show controller, Quote is created in quote model)
def send_invoice_email
quote = Quote.find(params[:invoice])
InvoiceMailer.send_invoice_email(quote, params)
end
And here is the method in my invoice mailer
def send_invoice_email(quote, params)
#quote = quote
mail(
to: current_user.email,
from: params[:from],
content_type: "text/html",
body: params[:body],
content_type: "text/html",
subject: params[:subject],
content_type: "text/html"
)
end
I changed a few things and now it seems to be working... Not sure why but I'll take it. Here are my current configurations..
Form is the same.
In my invoice controller I now have
def send_invoice_email
quote = Quote.find(params[:invoice])
InvoiceMailer.invoice_email(quote, params).deliver_now
end
In my invoice mailer I now have
def invoice_email(quote, params)
#user = quote.user
#quote = quote
#message = params[:body]
mail to: params[:to],
from: #user.email,
body: #message,
subject: params[:subject],
content_type: "text/html"
end
Related
<header>
<% include templates/header.ejs %>
</header>
<% include templates/announcement.ejs %>
<form>
<br><input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search a fort...">
</form><br>
<section id="placeList">
<div class="placeListBackground" id="placeListGet">
<ul id="placeCells">
<% placeData.forEach(function(placeData) { %>
<div class="placeContainer <%= placeData.category %>" class><img src= "<%= placeData.placeicon %>" alt="<%= placeData.placename %>" align="left" width="178" height="100"><span><%= placeData.placename %></span><p><%= placeData.clan %></p><p>Playing: <%= placeData.playing %></p><p class="sCategory"><%= placeData.category %></p></div>
<% }); %>
</ul>
</div>
</section>
I get an error saying "SyntaxError: missing ) after argument list in index.ejs while compiling ejs". Thing is, on my other computer this is exactly the same written code and works perfectly fine. Is it an issue with ejs or is there something I'm missing that may be significant?
You should try to following suggestion. It works for me so it should work for you.
<%- include('./templates/header.ejs');%>
<%- include('./templates/announcement.ejs');%>
I have to convert my form to not using nested association. In other words, instead of
<%= link_to_add_association f, :contacts, class: 'btn btn-primary', partial: 'projects/contact_fields', data: {
association_insertion_node: '.contact_fields', association_insertion_method: :append
} do %>
<i class="fas fa-plus"></i>
<% end %>
<%= f.fields_for :contacts do |contact| %>
<%= render 'projects/contact_fields', f: contact %>
<% end %>
I would like to be able to just pass in a string to be used as the container (similar to how you can with field_for).
<%= link_to_add_association 'contacts[]', 'projects/contact_fields', class: 'btn btn-primary', partial: 'projects/contact_fields', data: {
association_insertion_node: '.contact_fields', association_insertion_method: :append
} do %>
<i class="fas fa-plus"></i>
<% end %>
<% #contacts.each_with_index do |contact, index| %>
<%= fields_for "contacts[#{index}]", contact do |c| %>
<%= render 'projects/contact_fields', f: c %>
<% end %>
<% end %>
Cocoon is currently unable to edit/manage a collection. Cocoon is just helping the form-behaviour for nested-children functionality in rails, so there is no simple solution to edit an array or collection. On the other hand, this is in general pretty simple to implement without cocoon.
Very high level, do something like:
#contacts.each do |contact|
= render `contacts/edit`, contact: contact
= render `contacts/new`
so render the edit form for each existing contact, and render an empty new form. You will have to edit your controller functionality a little, because you will always re-render the complete collection/index page (with all existing contacts in the collection?).
So you can just render multiple forms on one page. Using turbolinks this will render fast and feel actually completely the same. You could use xhr to update only specific parts of the page, but to get started that is not even needed.
So I ended up following drifting ruby and using code from the cocoon gem to implement something myself. I hope others can benefit from it. Thank you nathanvda for the cocoon gem which helped me with the code below, really wish I could have used it:
add this to your app/helpers/application_helper.rb
def link_to_add_row(*args, &block)
if block_given?
link_to_add_row(capture(&block), *args)
else
#byebug
name, association, new_object, partial, html_options = *args
html_options ||= {}
html_options[:class] = [html_options[:class], "custom_add_fields"].compact.join(' ')
id = 'NEW_RECORD'
fields = fields_for("#{association}[#{id}]", new_object, child_index: id) do |builder|
#byebug
render( partial, f: builder)
end
fields = CGI.escapeHTML(fields).html_safe
link_to(name, '#', class: html_options[:class], data: {id: id, fields: fields})
end
end
add to your app/assets/application.js
$(document).on('click', '.custom_remove_fields', function(event) {
$(this).prev('input[type=hidden]').val('1');
$(this).closest('tr').hide();
return event.preventDefault();
});
$(document).on('click', '.custom_add_fields', function(event) {
var regexp, time;
time = new Date().getTime();
regexp = new RegExp($(this).data('id'), 'g');
$('.contact_fields').append($(this).data('fields').replace(regexp, time));
return event.preventDefault();
});
In your template you can use the following to render a partial for the collection:
<%= link_to_add_row('contacts', contact.new, 'contact_fields', class: 'btn btn-primary') do %>
<i class="fas fa-plus"></i>
<% end %>
This is how I render the partial with the collections in my template:
<tbody class="contact_fields">
<% #contacts.each_with_index do |contact, index| %>
<%= fields_for "contacts[#{index}]", contact do |c| %>
<%= render 'contact_fields', f: c %>
<% end %>
<% end %>
</tbody>
This is what my contact_fields.html.erb partial looks like.
<tr class="nested-fields">
<td>
<%= f.text_field :fullname, class: 'form-control invoke-contacts-search contact-fullname' %>
</td>
<td>
<%= f.text_field :email, class: 'form-control invoke-contacts-search contact-email' %>
</td>
<td>
<%= f.text_field :phone, class: 'form-control contact-phone' %>
</td>
<td>
<%= f.text_field :department, class: 'form-control contact-department' %>
</td>
<td>
<%= f.text_field :manager, class: 'form-control contact-manager' %>
</td>
<td>
<%= f.hidden_field :id %>
<%= f.hidden_field :_destroy %>
<%= link_to '#', class: 'btn btn-danger custom_remove_fields' do %>
<i class="fas fa-trash-alt"></i>
<% end %>
</td>
</tr>
I'm harp js user and im curious if its possible to call another parital to the harp js parameter?
I would like to proceed with modularization to reuse the code.
It is difficult to use the parital function of harp to insert data into a module of a particular module into another module.
This is my sources:
//component/button.ejs
<button><%= lable %></button>
//component/tab.ejs
<div class="tab">
<div class="tab__nav">
<% for(var i in locals.payload){ %>
<div class="tab__nav-item"><%- locals.payload[i].name %></div>
<% }; %>
</div>
<div class="tab__content">
<% for(var i in locals.payload){ %>
<div class="tab__content-item">
<div class="container">
<%- locals.payload[i].content %>
</div>
</div>
<% }; %>
</div>
</div>
//page.ejs
<%- partial("component/tab",{
payload: [
{
name:'tab1',
content:`
<div><%= partial("component/button.ejs",{label:"btn"})%></div>
`
},
{
name:'tab2',
content: `
<div>111111</div>
`
}
]}) %>
The command
mix phx.gen.html Blog Post posts title body:text
generates among other files the template form.html.eex for the add/edit posts form, which looks like this:
<%= form_for #changeset, #action, fn f -> %>
<%= if #changeset.action do %>
<div class="alert alert-danger">
<p>Oops, something went wrong! Please check the errors below.</p>
</div>
<% end %>
<div class="form-group">
<%= label f, :title, class: "control-label" %>
<%= text_input f, :title, class: "form-control" %>
<%= error_tag f, :title %>
</div>
<div class="form-group">
<%= label f, :body, class: "control-label" %>
<%= textarea f, :body, class: "form-control" %>
<%= error_tag f, :body %>
</div>
<div class="form-group">
<%= submit "Submit", class: "btn btn-primary" %>
</div>
<% end %>
The form_for function gets #action argument which is not present in the PostController, so where does it come from? I couldn't find.
In my installation I have a plug MyProject.Locale which redirects all unlocalized requests to localized ones like:
/posts --> /de/posts
And I have the :locale scope in my router
scope "/:locale", MyProject.Web, as: :locale do
pipe_through :browser
get "/", PageController, :index
resources "/posts", PostController
end
The default #action doesn't take the scope's locale chunk into account and sends the POST request to the /posts url, which is redirected by my MyProject.Locale plug to /de/posts as GET request (it uses the function Phoenix.Controller.redirect(to:...)). I want the form to send the POST request to the localized path.
So, can we override this #action argument for all resources somewhere in one place or do we have to provide it in each controller in render function call
render(conn, "new.html", changeset: changeset, action: action)
or the only option is to change the form templates for all resources?
My issue is that I keep on getting an argument error when trying to add subsections to my interview form which is nested under sections.
The Interview_kit has many sections and sections have many sub_sections. The sections belong to the interview_kit and the subsections belong to the section.
I would like to create all of this in the same form but am haveing no luck.
Is it possible to do this in Phoenix?
# Error
ArgumentError at GET /interview_Kit/new could not generate inputs for
:sub_sections from App.InterviewKit. Check the field
exists and it is one of embeds_one, embeds_many, has_one, has_many,
belongs_to or many_to_many
# This error is being shown when trying to render as a string in the method
link_to_sub_sections_field() below
# fields = render_to_string(__MODULE__, "sub_section.html", f: form)
# Schemas
schema "interview_kits" do
field :name, :string
field :description, :string
has_many :sections, AppSection
timestamps()
end
schema "sections" do
field :title, :string
timestamps()
belongs_to :interview_kit, App.InterviewKit
has_many :sub_sections, App.SubSection
end
schema "sub_sections" do
field :field_name, :string
belongs_to :section, App.Section
end
defmodule App.InterviewKitView do
def link_to_sub_section_fields() do
changeset = InterviewKit.changeset(%InterviewKit{sections: [%Section{sub_sections: [%SubSection{}]}]})
form = Phoenix.HTML.FormData.to_form(changeset, [])
fields = render_to_string(__MODULE__, "sub_section.html", f: form)
link "Add Sub Section", to: "#", "data-template": fields, id: "add_sub_section"
end
end
# sub_sections.html.eex
<%= inputs_for #f, :sub_sections, [multipart: true], fn fo -> %>
<div class="row">
<div class="col-md-11">
<%= input fo, :field_name %>
</div>
<div class="col-md-1">
<i class="fa fa-trash" aria-hidden="true"></i></h5>
</div>
</div>
<% end %>
# what I am trying to accomplish
interview_params = %{"_csrf_token" => "PDwZA==",
"_utf8" => "✓", "files" => "",
"interview_kit" => %{"description" => "<p>dsadasdasmoimoimadsads</p>",
"name" => "First Interview", "sections" => %{"0" => %{"name" => "sadasdsad"},
"sub_sections" => %{"0" => %{"field_name" => "sadasdsad"}}}}}
Issue was I was not reiterating over the sections form in my sub_section.html.eex
# sub_section.html.eex
# Correct way
<%= inputs_for #f, :sections, [multipart: true], fn fo -> %>
<div class="row">
<div class="col-md-11">
<%= inputs_for fo, :sub_sections, [multipart: true], fn po ->%>
<%= input po, :field_name %>
<% end %>
</div>
<div class="col-md-1">
<i class="fa fa-trash" aria-hidden="true"></i></h5>
</div>
</div>
<% end %>
# sub_section.html.eex
# Wrong way
<%= inputs_for #f, :sub_sections, [multipart: true], fn fo -> %>
<div class="row">
<div class="col-md-11">
<%= input fo, :field_name %>
</div>
<div class="col-md-1">
<i class="fa fa-trash" aria-hidden="true"></i></h5>
</div>
</div>
<% end %>
# section.html.eex
<%= inputs_for #f, :sections, [multipart: true], fn po -> %>
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">
<%= input po, :name %>
</div>
</div>
<div class="panel-body">
<% inputs_for po, :sub_sections, [multipart: true], fn fo -> %>
<div class="row">
<div class="col-md-11">
<%= input fo, :field_name %>
</div>
</div>
<% end %>
<h5><%= link_to_sub_section_fields() %></h5>
</div>
</div>
<!-- END PANEL -->
</div>
<%= link "Remove Section", to: "#", id: "delete_section" %>
</div>
<% end %>
#interview_kit_view.ex
def link_to_sub_section_fields() do
changeset = InterviewKit.changeset(%InterviewKit{sections: [%Section{sub_sections: [%SubSection{}]}]})
form = Phoenix.HTML.FormData.to_form(changeset, [])
fields = render_to_string(__MODULE__, "sub_section.html", f: form)
link "Add Sub Section", to: "#", "data-template": fields, id: "add_sub_section"
end
interview_kit.js
handleAdd() {
$(document).on("click", "#add_section, #add_sub_section", function(e) {
console.log($(e));
e.preventDefault();
let time = new Date().getTime();
let template = $(this).data("template");
let uniq_template = template.replace(/\[0\]/g, `[${time}]`);
uniq_template = uniq_template.replace(/_0_/g, `_${time}_`);
$(this).after(uniq_template);
});
}
I am not sure I fully understand why I have to reiterate over the sections form in my partial but it gives me the correct params on submit I was looking for.
%{"_csrf_token" => "AlgJcnNQw==",
"_utf8" => "✓", "files" => "",
"interview_kit" => %{"description" => "<p>dsadsadas</p>",
"name" => "name",
"sections" => %{"1495809951376" => %{"name" => "sadsadas",
"sub_sections" => %{"1495809951376" => %{"name" => "field_param"}}}}}}