Action Mailer with form that accepts_nested_attributes with Rails/HAML - ruby-on-rails

My model setup:
class Contact < ActiveRecord::Base
belongs_to :restaurant
end
class Restaurant < ActiveRecord::Base
has_many :contacts
accepts_nested_attributes_for :contacts
end
Contact class, trying to target: :email
class Contact < ActiveRecord::Base {
:id => :integer,
:first_name => :string,
:last_name => :string,
:role => :string,
:email => :string,
:phone => :string,
:webmaster_email => :string,
:restaurant_id => :integer,
:created_at => :datetime,
:updated_at => :datetime
}
My create action:
def create
stripe_token = PayingCustomer.build(restaurant_params)
#restaurant = Restaurant.new(restaurant_params)
#restaurant.payment_profile_id = stripe_token.id
#restaurant.generate_token
respond_to do |with|
if #restaurant.payment_profile_id != nil && #restaurant.save
RestaurantMailer.signup_confirmation(#restaurant).deliver
with.html {redirect_to restaurants_path(token: #restaurant.token)}
else
with.html {render :new }
end
end
end
I'm not sure how to target the email entered on form below:
=form_for #restaurant, html: {id: 'signup-form', multipart: true} do |f|
=field_set_tag %q{First, tell us about your restaurant.}, class: 'restaurant' do
=label_tag '', '', for: 'restaurant_name'
=f.text_field :name, placeholder: 'Restaurant Name'
=label_tag '', '', for: 'restaurant_address'
=f.text_field :address, placeholder: 'Street Address'
=label_tag '', '', for: 'restaurant_city'
=f.text_field :city, placeholder: 'City'
=label_tag '', '', for: 'restaurant_state_province'
=f.text_field :state_province, placeholder: 'State/Province'
=label_tag '', '', for: 'restaurant_country'
=select_tag 'restaurant[country]', "<option value='canada'>Canada</option><option value='usa'>United States</option>".html_safe, id: 'country'
=field_set_tag %q{Provide us with your contact info.}, class: 'contact' do
=f.fields_for :contacts do |contact_fields|
=label_tag '', ''
=contact_fields.text_field :first_name, placeholder: 'First Name'
=label_tag '', ''
=contact_fields.text_field :last_name, placeholder: 'Last Name'
=label_tag '', ''
=contact_fields.text_field :role, placeholder: 'Role at Restaurant'
=label_tag '', ''
=contact_fields.text_field :email, placeholder: 'Email'
=label_tag '', ''
=contact_fields.text_field :phone, placeholder: 'Phone'
=label_tag '', ''
=contact_fields.text_field :webmaster_email, placeholder: "Webmaster's Email (optional)"
My target is =contact_fields.text_field :email, placeholder: 'Email'
I'm trying to find out how I would write this in my mailer, with current setup, I'm getting wrong number of arguments (1 for 2)
My problem is right here:
class RestaurantMailer < ActionMailer::Base
default from: "from#example.com"
def signup_confirmation(restaurant, contact)
#greeting = "Hi"
#restaurant = restaurant
#contact = contact
mail to: contact.email, subject: "Sign up Confirmation"
end
end
Edit:
def signup_confirmation(restaurant)
#greeting = "Hi"
#restaurant = restaurant
#contact = restaurant.contact
mail to: #contact.email, subject: "Sign up Confirmation"
end
Results in:
NoMethodError in RestaurantsController#create
undefined method `contact' for #<Restaurant:0x007fd686c593b0>
Any help would be greatly appreciated!

it looks like your problem is in RestaurantMailer.signup_confirmation(#restaurant).deliver because you pass one argument, when signup_confirmation expects two.
in this case you could write:
def signup_confirmation(restaurant)
#greeting = "Hi"
#restaurant = restaurant
#contact = restaurant.contacts.first
mail to: #contact.email, subject: "Sign up Confirmation"
end

Related

Create multiple records in rails with collection_select

I am trying to build a messaging system where the user can select multiple recipients, and I would like to system to create a message for each of them. So far I got the controller like:
def create
#listmail = params[:recipient_ids]
#listmail.each do |v|
#message = current_user.messages.build(:title, :description, :user_id, recipient_id: v, :recipient_email, :tag_id, :industry, :strategy, :position, :aum)
#message.save!
end
if #message.save
redirect_to messages_path
else
render 'new'
end
end
The view:
<%= simple_form_for #message do |f| %>
<%= f.collection_select(:recipient_id, User.all, :id, :full_name, {}, class: "selectpicker", title: "Choose recipent", multiple: true, data: { style: "form-control", size: "20", width: "100%" }) %>
<%= f.input :title, label: "Message Title" %>
<%= f.cktext_area :description, label: "Message Body" , :input_html => {:rows => 15} %>
<%= f.button :submit, :class => 'btn-custom' %>
<% end %>
But I get the error:
/Users/apulvard/Desktop/villas/app/controllers/messages_controller.rb:40: syntax error, unexpected ',', expecting => ...ipient_id: v, :recipient_email, :tag_id, :industry, :strateg... ... ^ /Users/apulvard/Desktop/villas/app/controllers/messages_controller.rb:54: syntax error, unexpected keyword_end, expecting end-of-input
What am I not doing well please?
/Users/apulvard/Desktop/villas/app/controllers/messages_controller.rb:40:
syntax error, unexpected ',', expecting => ...ipient_id: v,
:recipient_email, :tag_id, :industry, :strateg... ...
You are passing an invalid hash to the build method. The hash must be a combination of key-value pairs. For example
Not valid:
h = {:email, :name, user: 1}
SyntaxError: (irb):4: syntax error, unexpected ',', expecting =>
h = {:email, :name, user: 1}
^
Valid:
h = {email:"", name: "", user: 1}
=> {:email=>"", :name=>"", :user=>1}
Solution:
You should change your hash to key-value pairs with the params that are coming to the create method. Usually this was the case before Rails 4. In Rails4, strong params were introduced. If you are using Rails 4+, you should define the strong params like so
def create
#listmail = params[:recipient_ids]
#listmail.each do |v|
#message = current_user.messages.build(message_params)
#message.recipient_id = v
#message.save!
end
if #message.save
redirect_to messages_path
else
render 'new'
end
end
private
def message_params
params.require(:message).permit(:title, :description, :user_id, :recipient_id, :recipient_email, :tag_id, :industry, :strategy, :position, :aum)
end
Moreover,
#listmail = params[:recipient_ids]
should be
#listmail = params[:message][:recipient_id]

5 form elements present, but only 4 are saving to the database. Rails

I am having a problem with my database. I am able to save all the elements of my form into the database but it is leaving out ":captcha" for some reason. :email, :first_name, :last_name and :user_message are all saving, but :captcha is not.
HTML form views/pages/index.html.erb
<%= form_for(#message) do |f| %>
<%= f.text_field :first_name, :class => "message_name_input message_input_default", :placeholder => " First Name" %>
<br><br>
<%= f.text_field :last_name, :class => "message_name_input message_input_default", :placeholder => " Last Name" %>
<br><br>
<%= f.text_field :email, :required => true, :class => "message_email_input message_input_default", :placeholder => " * Email" %>
<br><br>
<%= f.text_area :user_message, :required => true, :class => "message_user-message_input", :placeholder => " * Write a message" %><br><br>
<%= f.text_field :captcha, :required => true, :name => "captcha", :class => "message_input_default", :placeholder => " * #{#a} + #{#b} = ?" %><br><br>
<div id="RecaptchaField2"></div>
<%= f.submit "Send", :class => "messages_submit_button" %>
<% end %>
Pages Controller
class PagesController < ApplicationController
def index
#message = Message.new
#a = rand(9)
#b = rand(9)
session["sum"] = #a + #b
end
end
Messages Controller
class MessagesController < ApplicationController
def show
end
def new
#message = Message.new
end
def create
#message = Message.new(message_params)
if params["captcha"].to_i == session["sum"] && #message.save!
UserMailer.welcome_email(#message).deliver_now
redirect_to '/message_sent'
else
redirect_to '/'
end
end
private
def message_params
return params.require(:message).permit(:first_name, :last_name, :email, :user_message, :captcha)
end
end
Messages Migration
class CreateMessages < ActiveRecord::Migration
def change
create_table :messages do |t|
t.string :captcha
t.string :first_name
t.string :last_name
t.string :email
t.string :user_message
t.timestamps null: false
end
end
end
Schema
ActiveRecord::Schema.define(version: 20150822040444) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "messages", force: :cascade do |t|
t.string "captcha"
t.string "first_name"
t.string "last_name"
t.string "email"
t.string "user_message"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
Routes
Rails.application.routes.draw do
resources :pages
resources :messages
resources :admins
get '/' => 'pages#index'
get '/new' => 'messages#new'
post '/message_sent' => 'messages#create'
get '/message_sent' => 'messages#show'
end
EDITED Attempted this code, but instead of saving 4 elements, it executes the "else" statement and redirects as if it is not being saved at all.
Messages Controller
class MessagesController < ApplicationController
def show
end
def new
#message = Message.new
end
def create
#message = Message.new(message_params)
if params[:message][:captcha].to_i == session["sum"] && #message.save!
UserMailer.welcome_email(#message).deliver_now
redirect_to '/message_sent'
else
redirect_to '/'
end
end
private
def message_params
return params.require(:message).permit(:first_name, :last_name, :email, :user_message, :captcha)
end
end
Remove name attribute from here:
<%= f.text_field :captcha, :required => true, :name => "captcha", :class => "message_input_default", :placeholder => " * #{#a} + #{#b} = ?" %><br><br>
It happens because name parameter is generated by rails itself, and it's responsible to structure your query. Thus this erb line:
<%= f.text_field :first_name %>
Will generate this html:
<input type="text" name="message[first_name]">
And when you submit form it will produce query like this
{ message: { first_name: 'value_of_input' } }
But you provided custom name that overridden default behaviour and produces requests like this:
{ captcha: 'captcha_val', message: { first_name: 'some_val1', last_name: 'some_val2', ... } }
Then you extract message params from params:
def message_params
params.
require(:message).
permit(:first_name, :last_name, :email, :user_message, :captcha)
end
Finally you create message with this hash:
{ first_name: .., last_name: .., email: .., user_message: .. }

Rails 4 Nested Resources, Forms, strong params

I am trying to create a workout tracker. I have these nested resources
Routes.rb
resources :days do
resources :workouts
resources :meals
end
My models look fine:
Workout.rb
class Workout < ActiveRecord::Base
has_many :exercises
belongs_to :day
end
Day.rb
class Day < ActiveRecord::Base
has_many :workouts
has_many :meals
accepts_nested_attributes_for :workouts, :allow_destroy => true
accepts_nested_attributes_for :meals, :allow_destroy => true
end
The issue lies when I try to create a new workout..
../views/workouts/_form.html.haml
= form_for([#day, #workout]), html: {class: 'form-horizontal'}) do |f|
= f.input :workout, label: "What did you work out", input_html: { class: "form-control"}
= f.input :mood, label: "How do you feel", input_html: { class: "form-control"}
= f.hidden_field :day_id, value: params[:day_id], input_html: { class: "form-control"}
= f.submit
I cant seem to save the :day_id the workout is associated with the workout though using strong params to receive them.
WorkoutsController.rb
private
def workout_params
params.require(:workout).permit(:day_id, :name, :mood)
end
def find_day
#day = Day.find(params[:day_id])
end
Instead what gets saved is a nil for :day_id
Rails Console:
Workout id: 11, name: "Hey", mood: "no", day_id: nil, created_at: "2014-12-19 14:53:29", updated_at: "2014-12-19 14:53:29"
HELP?
PS - i tried to do
= form_for([#day, #workout]), as: :foo, html: {class: 'form-horizontal'}) do |f|
= f.input :workout, label: "What did you work out", input_html: { class: "form-control"}
= f.input :mood, label: "How do you feel", input_html: { class: "form-control"}
= f.hidden_field :day_id, value: params[:day_id], input_html: { class: "form-control"}
= f.submit
and then
def workout_params
params.require(:foo).permit(:day_id, :name, :mood)
end
But it just kept saying the :foo params where empty
The way your routes are set up, I am assuming that the day_id is being passed as a url params:
/days/:day_id/workouts
If that is the case, then you do not need to worry about #day in the form, nor the day_id in the workout_params
Form:
= form_for #workout, html: {class: 'form-horizontal'}) do |f|
= f.input :workout, label: "What did you work out", input_html: { class: "form-control"}
= f.input :mood, label: "How do you feel", input_html: { class: "form-control"}
= f.submit
Controller:
def create
#workout = #day.workouts.new(workout_params)
....
end
private
def workout_params
params.require(:workout).permit(:name, :mood)
end
def find_day
#day = Day.find(params[:day_id])
end

Making one nested form_for use two different controllers

I have two models #product and #photo with #photo nested in #product. I am only allowed to use one form to create both. I am using this JQuery plugin to handle photo upload being how it gives me a nice preview.
However the plugin has certain restrictions in my create action so I cannot use the product create action to handle both creating the photo and product.
Is it possible to have one nested for_for use two different controllers?
And how would i do it ?
my form (haml)
= form_for #product,:url => products_path, :html => { id: "fileupload", multipart: true } do |f|
%p
= f.text_field :name, placeholder: "Name"
%p
= f.text_field :price, class: "auto", data: { a_sign: "$ " }, placeholder: "Price"
%p
= f.text_field :description, placeholder: "Description"
%p
= f.fields_for :photos do |fp|
=fp.file_field :image
%br
.files{"data-target" => "#modal-gallery", "data-toggle" => "modal-gallery"}
%p.button.start
= f.submit
You can use accept_nested_attributes for to save associated data with only one create action.
Eg:-
class AlbumsController < ApplicationController
def new
#album = Album.new
#album.photos.build
end
def create
#album = Albums.new(params[:album])
#album.photos.build unless #album.photos.present?
if #album.save
flash[:notice] = "Successfully created albumn"
respond_with(#album, :location => albums_path())
else
flash[:error] = #album.errors.full_messages
render :new
end
end
end
Model:-
class Album < ActiveRecord::Base
has_many :photos, dependent: :destroy
accepts_nested_attributes_for :photos, allow_destroy: true, reject_if: proc {|attr| attr['image'].blank? }
end
class Photo < ActiveRecord::Base
belongs_to :album
end
View:-
= form_for #album,:url => albums_path, :html => {multipart: true } do |f|
%p
= f.text_field :name, placeholder: "Name"
%p
= f.text_field :price, class: "auto", data: { a_sign: "$ " }, placeholder: "Price"
%p
= f.text_field :description, placeholder: "Description"
%p
= f.fields_for :photos do |photo|
= photo.file_field :image
%br
.files
%p.button.start
= f.submit
Use ajax to firstly upload photo and after successful response continue with product.

How make a drop down menu reflect what's stored in it's corresponding db column in ruby on rails?

How do I make a drop down menu reflect what's stored in it's corresponding column in a database?
I have a dropdown menu for gender selection and it updates the database fine
but goes back to default option in select menu on refresh where as all my text fields are pulling db data fine.
<%= form_for #profile, :remote => true, do |f| %>
Username: <%= #profile.user.username %><br />
URL: http://site.com/<%= #profile.user.username %><br />
First Name: <%= f.text_field :first_name, %><br />
Last Name: <%= f.text_field :last_name, %><br />
I am: <%= f.select :gender, options_for_select([['Select Gender', ''],['Male','m'],['Female','f']]) %><br />
<%= f.submit 'update' %><br />
<% end %>
Any clue what I'm missing?
Kind regards
Here's my model:
class Profile < ActiveRecord::Base
belongs_to :user
attr_accessible :first_name, :last_name, :gender, :motd
# Local Variables
# Regex Variables
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
alpha_regex = /^[a-zA-Z]*$/
alpha_numeric_regix = /^[a-zA-Z0-9_]*$/
#Form Validation
validates :first_name, :presence => true,
:length => { :minimum => 2, :maximum => 15 },
:format => {
:with => alpha_regex,
:message => "Your first name must contain letters only"
}
validates :last_name, :presence => true,
:length => { :minimum => 2, :maximum => 15 },
:format => {
:with => alpha_regex,
:message => "Your last name must contain letters only"
}
validates :gender, :presence => true,
:inclusion => {
:in => %w( m f ), :message => "Are you male or female?"
}
end
Update method from controller
def update
respond_to do |format|
if #profile.update_attributes(params[:profile])
format.js { render :js => "window.location = '#{settings_edit_profile_path}'" }
flash[:success] = "Profile updated"
else
format.js { render :form_errors }
end
end
end
options_for_select has a special syntax for selecting a value:
<%= f.select :gender, options_for_select([['Select Gender', ''],['Male','m'],['Female','f']], "#{#profile.gender}") %>
might work like you expect.
Or you could create a Gender model and use collection_select which does this by default:
<%= f.collection_select :gender, Gender.all, :value, :description, :prompt => true %>

Resources