I am making a little app based on futureme.org for practice. The user goes to a page, sees a form, fills it out with email, subject, message, and a delivery date. Then the app delivers their message (email) on that date.
The problem I am having, is I am not sure how to set up the delivery date option in the model & in the view (ie. does rails have a date option?). Here is my code;
Letter.rb
class Letter < ActiveRecord::Base
VALID_EMAIL_REGEX = /\A[\w+\-,]+#[a-z\d\-.]+\.[a-z]+\z/i
validates_presence_of :email, presence: true, format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates_length_of :subject, presence: true, :maximum => 30
validates_presence_of :message
validates_presence_of :deliver_on #not sure if this is right
end
Letters_Controller.rb
class LettersController < ApplicationController
def create
#letter = Letter.new(letter_params)
if #letter.save
LetterMailer.letter_confirm(#letter).deliver
redirect_to letters_path, :notice => "Your letter was sent!"
else
render "welcome/home"
end
end
private
def letter_params
params.require(:letter).permit(:email, :subject, :message)
end
end
lettermailer.rb
class Lettermailer < ActionMailer::Base
default from: "futureself#example.com"
def letter_confirm(letter)
mail(to: #letter.email, subject: "Thanks from Future Self")
end
def letter_email(letter)
#letter = letter
#url = 'http://futureself.herokuapp.com'
mail(to: #letter.email, subject: #letter.subject)
end
end
Home Page Form;
<%= form_for #letter, :html => {:class => 'form-horizontal'} do |f| %>
<% if #letter.errors.any? %>
<div class="error_messages">
<h3><%= pluralize(#letter.errors.count, "error")%> stopped this message from being saved</h3>
<ul>
<% #letter.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :subject %><br />
<%= f.text_field :subject %><br />
</div>
<div class="field">
<%= f.label :message, "Message" %><br />
<%= f.text_area :message, size: "100x10" %>
</div>
<!-- Deliver on Option -->
<div class="field"><%= f.submit "Submit", class: "btn btn-small btn-primary" %></div>
<% end %>
</body>
</html>
Any help at all would be great.
You need a job queue, I would suggest using DelayedJob as it's about as simple as it gets (if you are using ActiveRecord) https://github.com/collectiveidea/delayed_job
Then in your LessonsController
LetterMailer.delay(run_at: #letter.deliver_on).letter_confirm(#letter)
This assumes deliver_on is a DateTime object.
Couple things you might want to consider:
Rails Cast on DelayedJob http://railscasts.com/episodes/171-delayed-job-revised
if someone changes the letter model before it's delivered
TimeZones http://railscasts.com/episodes/106-time-zones-revised
Server implementation of DelayedJob (can be tricky)
Other job queues that are good but rely on redis are http://sidekiq.org/ and https://github.com/resque/resque
Validations
I like to use the validates_timeliness gem. So you can do things like
validates_date :deliver_on, :before => lambda { Time.zone.now + 1.year },
:before_message => "must be earlier one year from today",
:on_or_after => lambda { Time.zone.now.end_of_day },
:on_or_after_message => "must be after today"
Form
You can use jquery-ui-rails
f.input :deliver_on, as: :string, label: "Date of delivery (dd/mm/yyyy)", input_html: {class: "jquery-ui-date", value: f.deliver_on ? l(f.deliver_on) : nil }
Don't get me started on RegEx for email. Try googling it ;)
And yeah like #mattsmith said check out delayed job.
Related
I'm having a problem in the model saving with nested attributes.
In the app, there's a Customer, that have 1..n Contacts witch in turn have 1..n Telephones.
I've searched a lot before asking here, and decided to make it save only the Contact first. Well, at first the Customer is stored, but Contact is not. From what I read there's no need to repeat the ... contacts.build from new function in the create, and that the line "#customer = Customer.new(customer_params)" would create and store them both.
Why it's not working? (That's the first question.)
After some modifications and debugging, I found that when I set a second line building Contact (...contacts.build(customer_params[:contacts_attributes])) it's not saved because of an error of 'unknown attribute'. That's because between the hash :contacts_attribute and the content of it, it's added another hash, called ':0' (?). The structure of the hash that comes from the form is this :
":contacts_attribute[:0[:name, :department, :email]]"
I imagine that this hash :0 is for adding more than one Contact instance, that will come in hashes :1, :2 etc.
There's a way to store the Contact instance by getting this :0 hash? (How do I access this hash? Is it "... :contacts_attribute[0]"?)
Below is the relevant code.
Thanks for the attention!
customer.rb
class Customer < ActiveRecord::Base
...
has_many :contacts
accepts_nested_attributes_for :contacts, reject_if: lambda {|attributes| attributes['kind'].blank?}
...
def change_by(user_id)
update_attributes(changed_by: user_id, deleted_at: Time.now, updated_at: Time.now)
end
def delete(user_id)
update_attributes(status: false, changed_by: user_id, deleted_at: Time.now, updated_at: Time.now)
end
private
...
end
customers_controller.rb
class CustomersController < ApplicationController
def new
#customer = Customer.new
#customer.contacts.new
end
def create
user_id = session[:user_id]
#customer = Customer.new(customer_params)
if #customer.save
#customer.change_by(user_id)
flash[:success] = "Cliente cadastrado com sucesso!"
redirect_to customers_url
else
render 'new'
end
end
private
def customer_params
params.require(:customer).permit(:razao_social, :nome, :CPF_CNPJ,
:adress_id, :email_nota, :transporter_id, :observacao,
contacts_attributes: [:nome, :setor, :email])
end
Form
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for #customer do |f| %>
<%= f.label "Dados Básicos" %>
<div class="well">
<%= f.label :razao_social, "Razão Social" %>
<%= f.text_field :razao_social %>
<%= f.label :nome, "Nome" %>
<%= f.text_field :nome %>
<%= f.label :CPF_CNPJ, "CPF/CNPJ" %>
<%= f.text_field :CPF_CNPJ %>
<%= f.label :email_nota, "Email para nota" %>
<%= f.email_field :email_nota %>
<%= f.label :observacao, "Observações" %>
<%= f.text_area :observacao %>
</div>
<%= f.fields_for :contacts do |k| %>
<%= k.label "Contato" %>
<div class="well">
<%= k.label :nome, "Nome" %>
<%= k.text_field :nome %>
<%= k.label :setor, "Setor" %>
<%= k.text_field :setor %>
<%= k.label :email, "Email" %>
<%= k.email_field :email %>
</div>
<% end %>
<%= f.submit "Cadastrar Cliente", class: "btn btn-primary" %>
<% end %>
</div>
reject_if: lambda {|attributes| attributes['kind'].blank?}
No sign of :kind in your form or your customer_params
This might have something to do with it.
Other than that, if you need an add/remove relationship for contacts, check out the cocoon gem. If you only need one, then build that into your fields for:
<%= f.fields_for :contacts, #customer.contacts.first || #customer.contacts.build do |k| %>
The form will then be specific to a single instance of contact.
There's a way to store the Contact instance by getting this :0 hash?
(How do I access this hash? Is it "... :contacts_attribute[0]"?)
You don't need to access it, that's what the accepts_nested_attributes is for. The rest of your code looks ok so sort out the rejection issue at the top and come back if there are still problems, and post the log output - specifically the params hash for the request!
I'm trying to build my first contact form, that would send someone's name, email and message to my email address to me. I've seen quite a lot of tutorials and answered questions on stackoverflow, but it didn't help me to fix the problem I'm having. I know it has something to do with the routing but I can't figure what and why.
I'm getting the following error:
Routing Error
uninitialized constant ContactController
Here are my files :
routes.rb
match '/send_mail', to: 'contact#send_mail', via: 'post'
match '/mail', to: 'contact#contact', via: 'get'
controllers/contacts_controller.rb
def send_mail
name = params[:name]
email = params[:email]
body = params[:comments]
ContactMailer.contact_email(name, email, body).deliver
redirect_to contact_path, notice: 'Message sent'
end
mailers/contact_mailer.rb
class ContactMailer < ActionMailer::Base
default to: 'mymail#gmail.com'
def contact_email(name, email, body)
#name = name
#email = email
#body = body`enter code here`
mail(from: email, subject: 'Contact Request')
end
end
views/contact.html.twig
<div class="container-content">
<div class="container">
<%= form_tag(send_mail_path) do %>
<div class="form-group">
<%= label_tag 'name', 'Name' %>
<%= text_field_tag 'name', nil, class: 'form-control', placeholder: 'John Doe' %>
</div>
<div class="form-group">
<%= label_tag 'email', 'Email' %>
<%= email_field_tag 'email', nil, class: 'form-control', placeholder: 'johndoe#domain.com' %>
</div>
<div class="form-group">
<%= label_tag 'comments', 'Comments' %>
<%= text_area_tag 'comments', nil, class: 'form-control', rows: 4, placeholder: 'How can I help you?' %>
</div>
<%= submit_tag nil, class: 'btn btn-default btn-about' %>
<% end %>
</div>
</div>
views/contact_email.html.erb
<!DOCTYPE html>
<html>
<head>
<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<p>Mail received from <%= "#{ #name } (#{ #email }):" %></p>
<p><%= #body %></p>
</body>
</html>
config/initializers.rb
module Contact
class Application < Rails::Application
config.action_mailer.delivery_method = :sendmail
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
config.active_record.raise_in_transactional_callbacks = true
end
end
initializers/stmp_config.rb
config.action_mailer.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:domain => "gmail.com",
:user_name => "mymail#gmail.com",
:password => "password",
:authentication => :login,
:enable_starttls_auto => true
}
As I'm newbie in the rails world, I'm not sure at all of what I'm doing, but I've seen a lot of tutorials where people had a code similar to mine, but no one seems to have this problem
Where did i go wrong ?
Thank you in advance
You may want to change your routes.rb as follows (contacts instead of contact):
match '/send_mail', to: 'contacts#send_mail', via: 'post'
match '/mail', to: 'contacts#contact', via: 'get'
Thats one way to create a contact form - however its not really a Rails app. Its just an app that happens to be using Rails.
This is how you can use the Rails conventions to make this more robust and less messy.
Model
Lets generate a model and migration:
$ rails g model enquiry name:string email:string body:text
Then we run the migration:
$ rake db:migrate
So why create a model if we are just sending an email? Because email fails. And you don't want to lose important enquiries from potential customers.
We also want our model to validate that the user provides the required fields:
# app/models/enquiry.rb
model Enquiry < ActiveRecord::Base
validates_presence_of :name, :email, :body
validates_format_of :email, with: /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
end
Controller
Lets create a RESTful route:
# config/routes.rb
# ...
resources :enquiries, only: [:new, :create]
Note that we are calling it enquiries. Instead of using an procedure oriented send_contact route we have the resource enquiries which gives us conventions for how to show, create and update it.
You can see what routes are generated with $ rake routes.
See Resource Routing: the Rails Default.
Lets create a controller for our new route:
# app/controllers/enquiries_controller.rb
# note controllers use the plural form
class EnquiriesController < ApplicationController
# GET '/enquiries/new'
def new
#enquiry = Enquiry.new
end
# POST '/enquiries'
def create
#enquiry = Enquiry.new(enquiry_params)
if #enquiry.save
ContactMailer.contact_email(name, email, body).deliver
redirect_to root_path, success: 'Thanks for getting in touch, we will look into it ASAP.'
else
render :new
end
end
private
def enquiry_params
params.require(:enquiry).permit(:name, :email, :body)
end
end
View
We also need a form:
# app/views/enquiries/new.html.erb
<%= form_for(#enquiry) do |f| %>
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<div class="form-group">
<%= f.label :email %>
<%= f.email_field :name %>
</div>
<div class="form-group">
<%= f.label :body %>
<%= f.text_area :body %>
</div>
<%= f.submit %>
<% end %>
By using a form builder and a model our form will automatically "play back" the values if the user submits an invalid form.
Your problem in 'ContactController' - it's must be in plural: 'ContactsController'!
So I'm having an issue setting a primary image for my Dress object via a form.
The form allows the user to edit the dress details and then add/remove images to the form (using nested_form) and for each of them set a label and assign a primary image.
Everything works so far except for setting the primary image via radio buttons.
Dress Model:
class Dress < ActiveRecord::Base
has_many :dress_images
has_one :primary_dress_image, :class_name => "DressImage", :conditions => { :is_primary => true }
accepts_nested_attributes_for :dress_images, :allow_destroy => true
validates :name, :presence => true, :length => { :maximum => 99 }
end
DressImage Model
class DressImage < ActiveRecord::Base
belongs_to :dress
# Same as:
# def self.primary
# where(:is_primary => true)
# end
scope :primary, where(:is_primary => true)
# clear old primary if:
# this is a new record
# this is existing and is_primary has been set to true
before_save :clear_primary,
:if => Proc.new{ |r| (r.new_record? && r.is_primary) || (r.is_primary_changed? && r.is_primary) }
validates :label, :presence => true, :length => { :maximum => 60 }
validates :caption, :length => { :maximum => 200 }
mount_uploader :image, ImageUploader
def clear_primary
DressImage.update_all( {:is_primary => false}, :dress_id => self.dress_id )
end
end
Dress edit form
<h1>Dress</h1>
<% #dress.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %> <%#= f.label :name %>
<%= nested_form_for #dress, :as => :dress, :url => { :action => :update }, :html=>{ :multipart => true } do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :description %>
<%= f.text_area :description %>
<%= f.fields_for :dress_images do |dress_image_form| %>
<div class="dress-image">
<%= image_tag dress_image_form.object.image_url(:thumb) %>
<%= dress_image_form.text_field :label %>
<%= dress_image_form.file_field :image %>
<div class="primary-image-radio">
<%= dress_image_form.label :is_primary, "Main Image" %>
<%= f.radio_button :primary_dress_image_id, dress_image_form.object.id %>
</div>
<p>
<%= dress_image_form.link_to_remove "Remove this attachment" %>
</p>
</div>
<% end %>
<%= f.link_to_add "Add Photo", :dress_images %>
<%= f.submit "Save Dress" %>
<% end %>
With this radio button, the primary_dress_image_id attribute is set on the Dress object, but #dress.primary_dress_image gives a different result to the ID.
If I change the radio button to <%= dress_image_form.radio_button :is_primary, true %> it works better but because the name of each radio button is different, they are not treated as the same group.
I'm new to rails so I might be missing something completely obvious or doing it all wrong.
Here's one solution.
Add a hidden input to each of your nested field groups. Use a radio_button_tag instead of radio_button to make sure they are in the same group:
<div class="dress-image">
<%= dress_image_form.hidden_field :is_primary, :class => 'primary-image' %>
...
<%= radio_button_tag "select_primary_image", true, dress_image_form.object.is_primary? %>
...
</div>
Then add some javascript to update the hidden field according to the radio button selection:
$("body").on "change", ".primary-image-radio input:radio" ->
$(#).closest(".dress-image").find(".primary-image").val( $(#).is(":checked") )
You might need to modify the code a little because it's just an untested quick example, but it should give you an idea.
So I ended up using this method: <%= dress_image_form.radio_button :is_primary, true %> and using jquery to deselect all the other radio buttons when one is clicked.
This seems like a bit of a hacky method to me - there must be a purely Rails way of doing this without having to resort to JS? Until I find a better one, I'm going to stick with this solution.
I am not really sure what I am doing wrong.
I see that quite many people have similar problems:
Rails contact form not working,
Rails 3 Contact Form, undefined method?,
Contact Us form in Rails 3 and etc.
Even tough I also see that quite many consider this very simple - to build a contact form.
Been trough popular actionmailer guides: http://guides.rubyonrails.org/action_mailer_basics.html,
http://railscasts.com/episodes/206-action-mailer-in-rails-3
I am not really a developer, so I find this quite confusing.
Anyway, I need to build a simple contact form, to just send the message as an email for a email account of mine. I don't want to store the messages in my db.
Here's my code:
/app/models/message.rb
class Message
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :name, :email, :content
def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
end
def persisted?
false
end
end
app\controllers\messages_controller.rb
class MessagesController < ApplicationController
def new
#message = Message.new
end
def create
#message = Message.new(params[:message])
MessageMailer.send(#message).deliver
flash[:notice] = "Message sent! Thank you for contacting us."
redirect_to root_url
end
end
/app/mailer/message_mailer.rb
class MessageMailer < ActionMailer::Base
default :to => "emils.veveris#thrillengine.com"
def send(message)
#message = message
mail( :subject => " Test ", :from => #message.email ) do |format|
format.text
end
end
end
app/views/messages/new.html.erb
<h1> "Contact Us" </h1>
<%= form_for #message do |f| %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.label :email %><br />
<%= f.text_field :email %>
</p>
<p>
<%= f.label :content, "Message" %><br />
<%= f.text_area :content %>
</p>
<p><%= f.submit "Send Message" %></p>
<% end %>
app/views/message_mailer/sent.text.erb
Message sent by <%= #message.name %>
<%= #message.content %>
and development.rb
N1::Application.configure do
# Don't care if the mailer can't send
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
end
I don't see any errors in log file and I don't receive any error messages.
The mail is just not delivered.
Can You please tell me what I am doing wrong?
Thanks!
This is a little old but maybe some of the concepts can help you...it's pretty much exactly what you're trying to do.
http://railscasts.com/episodes/193-tableless-model
I'm really new to both ruby on rails and programming. I am trying to develop an application but i am stucked now. I was watching http://railscasts.com/episodes/196-nested-model-form-part-1 to make nested model forms but i am having an error. My problem details are as follows;
I have employers model, and employers model has_many interviews, and interview model has_many customquestions. I'm trying to create a form through which i will collect info to create interview. Although i made all necessary assosications, when i submit the form it raises error saying that "Customquestions interview can't be blank". I am kinda sure that it is because of that i miss some code in interview controller. Below you can see my interview controller and the form template that i am using to submit info.
Interview Controller
class InterviewsController < ApplicationController
before_filter :signed_in_employer
def create
#interview = current_employer.interviews.build(params[:interview])
if #interview.save
flash[:success] = "Interview created!"
redirect_to #interview
else
render 'new'
end
end
def destroy
end
def show
#interview = Interview.find(params[:id])
end
def new
#interview = Interview.new
3.times do
customquestion = #interview.customquestions.build
end
end
end
Form which i use to submit info:
<%= provide(:title, 'Create a new interview') %>
<h1>Create New Interview</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(#interview) do |f| %>
<%= render 'shared/error_messages_interviews' %>
<%= f.label :title, "Tıtle for Interview" %>
<%= f.text_field :title %>
<%= f.label :welcome_message, "Welcome Message for Candidates" %>
<%= f.text_area :welcome_message, rows: 3 %>
<%= f.fields_for :customquestions do |builder| %>
<%= builder.label :content, "Question" %><br />
<%= builder.text_area :content, :rows => 3 %>
<% end %>
<%= f.submit "Create Interview", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
In interview model, i used accepts_nested_attributes_for :customquestions
Interview Model
class Interview < ActiveRecord::Base
attr_accessible :title, :welcome_message, :customquestions_attributes
belongs_to :employer
has_many :customquestions
accepts_nested_attributes_for :customquestions
validates :title, presence: true, length: { maximum: 150 }
validates :welcome_message, presence: true, length: { maximum: 600 }
validates :employer_id, presence: true
default_scope order: 'interviews.created_at DESC'
end
The validation error gets raised in the customquestions model because (I assume) it validates :interview_id. The problem is that interview_id won't get set until the parent object (Interview) is saved, but validations for customquestion are run before Interview is saved.
You can let cusomtquestions know about this dependency by adding the option :inverse_of=> :customquestions to belongs_to :interview in the customquestions model.