I want to build feedback form to send it body to some e-mail box. Each form belongs to many pages (but page has only one form), has one title and body and can have one e-mail. Now it works like this:
app/views/shared/_custom_form.html.slim
= form_for #feedback, method: :post, url: feedback_path, remote: true do |f|
fieldset.b-form-field style='display:none'
= f.text_field :email, value: #feedback.email
fieldset.b-form-field
= f.label :title, "Title"
= f.text_field :title, value: #feedback.title
fieldset.b-form-field
= f.text_field :body, value: #feedback.body
fieldset.b-form-field
= f.submit "Send"
app/controllers/pages_controller.rb
class PagesController < FrontendController
def show
#feedback = Feedback.new
end
end
app/controllers/feedback_controller.rb
class FeedbackController < FrontendController
def new
#feedback = Feedback.new
end
def create
#feedback = Feedback.new(feedback_params)
respond_to do |format|
if #feedback.valid?
eml_sett =
if feedback_params[:email]
feedback_params[:email]
else
setting_value(:main_email)
end
if eml_sett.present?
FeedbackMailer.feedback_message(#feedback, eml_sett).deliver
end
end
end
end
def feedback_params
params.require(:feedback).permit(:title, :body, :email)
end
So, #feedback is created in my view, and then it goes from page controller to feedback_controller where it will be sended to form owner or to default email address. It work perfectly (i know, it is better to use hidden_field, but it is raw project), but i want to totally hide e-mail address from html code. So, i tried in my view:
= form_for #feedback(email: 'test#test.com')...
= form_for #feedback...
- #feedback.email = 'test#test.com'
= form_for Feedback.new(email: 'test#test.com')
But nothing helped. If I run '- puts #feedback.email' in my view, it returns email value, but in feedback controller 'puts feedback_params[:email]' returns nothing and form is sended to default email box. What am I doing wrong? Where is the mistake? Using Rails 4.1.8/Ruby 2.2.0.
I am guessing that your pages#show action displays a generic page with a 'sign up for newsletter' type of form. However, since you want to capture more data, right now you want to direct the user flow to a feedback page, which is served at feedback#new.
If so, what you can do is make the pages#show form submit a GET request on feedback#new, something like this:
= form_for :feedback, url: new_feedback_path, method: :get do |f|
= f.input :email
= f.submit
In your feedback#new action, you can do something like this:
def new
#feedback = Feedback.new(feedback_params)
end
If you use require(:feedback) in your strong params, then this will be a problem if you want to allow access to the new action without first supplying an email, but I'll leave that for you to decide if you want to support that.
What you are saying about using hidden fields, well you can't avoid it since it is user input. So whether or not you enable it as an editable input field, or keep it hidden, the user can supply any value whatsoever on the first page, which is pages#show.
If what you need is to hide the email, then yes you don't need a form field anywhere. This is what you do in your controller:
def create
#feedback = Feedback.new(feedback_params)
FeedbackMailer.feedback_message(#feedback).deliver
end
And in your mailer:
class FeedbackMailer < ApplicationMailer
def feedback_notification(feedback)
#feedback = feedback
mail(to: admin_email, from: #feedback.email, subject: #feedback.title)
end
private
def admin_email
ENV['ADMIN_EMAIL']
end
end
try this:
form_for #feedback... do |f|
= f.hidden_field :email
Related
I am trying to create a custom form_for where I check if the record exists in the table or not. I've done tons of research but haven't come up with anything useful.
My current approach is to create a simple search form and display all similar records. However, that's not what I am looking for. Ideal scenario would be:
Get record's name from form_for
Check if this record present
If present - redirect to one page. If not - redirect to another page
My controller:
def validate_name
#room = Room.new
name = params[:name]
if name != nil
puts "Redirect to page A"
else
puts "Redirect to page B"
end
end
The problem here is that whenever the user comes to the page it automatically triggers the code above. My goal is to create a form validation that tries to find the exact record and then redirect based on if else condition.
Current form_for:
= form_for(Room.new, url: name_room_path, method: :get, action: :validate_name) do |f|
= f.text_field :name
= f.submit
I am sure that my form is incorrect too because I got lost. I found ways to create custom forms but can't figure out how to trigger database check based on the user's input.
PS: these are not new or update actions.
Thank you for your help and time.
Try this:
class RoomsController < ActionController::Base
def validate_name
if params[:name] && Room.where(name: params[:name]).last.present?
puts "Redirect to page A"
elsif params[:name] && Room.where(name: params[:name]).last.nil?
puts "Redirect to page B"
end
end
end
in routes.rb:
get '/rooms/validate_name', to: 'rooms#validate_name'
in view:
<%= form_tag(rooms_validate_name_path, :method => :get )do %>
<%= text_field_tag :name %>
<%= submit_tag %>
<% end %>
I'm trying to figure out how to setup a mailer class in my Rails 4 app.
I have made a mailer called admin_notes. I want to use it to send emails to the internal team when certain actions are taken across the site.
In my mailer/admin_note.rb, I have:
class AdminNote < ApplicationMailer
def unknown_organisation(organisation_request, user_full_name, name)
#organisation_request =
#user_full_name =
#organisation_request.name =
# #greeting = "Hi"
mail( to: "test#testerongmail.com",from: "test#testerongmail.com", subject: "A new organisation")
end
end
I have an organisation_requests model. It has:
class OrganisationRequest < ActiveRecord::Base
belongs_to :profile
delegate :user_full_name, to: :profile, prefix: false, allow_nil: true
The organisation request table has an attribute called :name in it.
When a new organisation request is created, I want to send an admin note to the internal team, alerting someone to start a process.
I'm struggling to figure out how I define the three variables in the mailer method.
I plan to add the send email call to the create action in the organisation requests controller.
How can I set these variables?
Form to create an organisation request is:
<%= simple_form_for(#organisation_request) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :organisation_id, collection: #all_organisations << ['other', nil] %>
</div>
<div class="form-inputs">
<%= f.input :name %>
</div>
<div class="form-actions">
<%= f.button :submit, "Create", :class => 'formsubmit' %>
</div>
<% end %>
NEW ATTEMPT:
I have a create action in my organisation controller, I added this service class request for an email:
def create
#organisation_request = OrganisationRequest.new(organisation_request_params)
#organisation_request.profile_id = current_user.profile.id
if #organisation_request.save
NewOrgRequestService.send_unknown_organisation_requested_flag(organisation_request)
return redirect_to(profile_path(current_user.profile),
flash[:alert] => 'Your request is being processed.')
else
# Failure scenario below
#all_organisations = Organisation.select(:title, :id).map { |org| [org.title, org.id] }
render :new
end
end
I then have a services/organisations requests/NewOrgRequestService.rb
class OrganisationRequest < ActiveRecord::Base
class NewOrgRequestService
attr_accessor :organisation_request
def self.send_unknown_organisation_requested_flag(organisation_request)
if #organisation_request.name.present?
AdminNote.unknown_organisation_requested(organisation_request, user_full_name, name).deliver_later
end
end
end
end
The AdminNote mailer has:
class AdminNote < ApplicationMailer
layout 'transactional_mailer'
def unknown_organisation_requested(organisation_request, user_full_name, name)
#organisation_request = #organisation_request
#user_full_name = #organisation_request.user_full_name
#name = organisation_request.name
# #greeting = "Hi"
mail
to: "test#testerongmail.com",from: "test#testerongmail.com", subject: "A new organisation"
end
end
This doesnt work, but I'm wondering if Im on the right track? Im not sure if the create action in the controller needs to have some kind of reference to the services/organisation_requests/ path that gets to the file??
I think I may have made a bigger mess than I started with - but I'm out of ideas for things to try next.
This may help you.
In your mailer method
def unknown_organisation(org,user)
#org = org
#user = user
mail(to: "test#testerongmail.com",from: "test#testerongmail.com", subject: "A new organisation")
end
In your controller method after saving organization_request and this is how you set your variable. You can pass variable you want.
AdminNote.unknown_organization(#organization_request, current_user).deliver_now
In your mailer template access passed value as you do in action view. And this is how you use your variable.
<%= #org.name %>
<%= #org.full_name %>
Hope this helps
If you want to queue message or send later you can use ActiveJob to send mails in the background.
For more, see http://guides.rubyonrails.org/active_job_basics.html
I know I am super late but here I go.
I understand that you are trying to send in some parameters (values) to mailer so that you can use it while sending an email.
To do so you just need to define a mailer method that accepts some parameters. What you have done is right in your AdminNote Mailer unknown_organization method.
Let's get to your NEW ATTEMPT.
Everything you have done there seems about right except you are passing an undefined variable organization_request. You have created an instance variable #organization_request but you are passing something that is not defined. Here
NewOrgRequestService.send_unknown_organisation_requested_flag(organisation_request)
That is your first problem. This can be improved as:
Your Organizations#create
def create
#organisation_request = OrganisationRequest.new(organisation_request_params)
#organisation_request.profile_id = current_user.profile.id
if #organisation_request.save
#organisation_request.send_unknown_organisation_requested_flag
redirect_to(profile_path(current_user.profile),
flash[:alert] => 'Your request is being processed.')
else
# Failure scenario below
#all_organisations = Organisation.select(:title, :id).map { |org| [org.title, org.id] }
render :new
end
end
And your model can be as follows:
class OrganisationRequest < ActiveRecord::Base
def send_unknown_organisation_requested_flag
if self.name.present?
AdminNote.unknown_organisation_requested(self).deliver_later
end
end
end
I don't know why you are defining a class inside your model class.
Your Mailer should look like below:
class AdminNote < ApplicationMailer
layout 'transactional_mailer'
def unknown_organisation_requested(organisation_request)
#organisation_request = organisation_request
#user_full_name = #organisation_request.user_full_name
#name = organisation_request.name
# #greeting = "Hi"
mail
to: "test#testerongmail.com",from: "test#testerongmail.com", subject: "A new organisation"
end
end
There are a lot of typos and method implementation errors here.
I'm trying to make simple app. I input my first name and last name to simple <%= form_for #data do |f| %> rails form and after submitting it, app should render simple text like this. My first name is <%= data.first_name %> and my last name is <%= data.last_name %>. I don't know why but my app is saying this error:
undefined local variable or method `data' for
It's probably saying it because no params are passed to view.
Here is my code.
routes.rb
resources :data, only: [:new, :create, :index]
data_controller.rb
class DataController < ApplicationController
def new
#data = Data.new
end
def index
end
def create
#data = Data.new(data_params)
if #data.valid?
redirect_to #data
else
render :new
end
end
private
def data_params
params.require(:data).permit(:first_name, :second_name)
end
end
/views/data/new.html.erb
<%= form_for #data do |f| %>
<%= f.label :first_name %>
<%= f.text_field :first_name %>
<%= f.label :second_name %>
<%= f.text_field :second_name %>
<%= f.submit 'Continue', class: 'button' %>
<% end %>
/views/data/index.html.erb
<h2>Coolest app ever :D</h2>
<p>My first name is: <%= data.first_name %>.</p>
<p>And my second name is: <%= data.second_name %>.</p>
/models/data.rb
class Data
include ActiveModel::Model
attr_accessor :first_name, :second_name
validates :first_name, :second_name, presence: true
end
Please help to find out why params are not passing to next page. Thanks anyways :D
Your view should look like this:
<h2>Coolest app ever :D</h2>
<p>My first name is: <%= #data.first_name %>.</p>
<p>And my second name is: <%= #data.second_name %>.</p>
Also, I would suggest that calling a model something generic like Data is not a very Rails-y approach. Generally, domain models correspond to real-world things like User and Article, which are easy to understand and relate to. It'll get confusing quite fast if you use need to make another model and want to call it Data2 or something :)
Edit:
Since you specified that you do not wish to use the database, I would recommend passing in the object params through the redirect:
redirect_to(data_path(data: #data))
and in your controller's index method:
def index
#data = Data.new(params[:data])
end
Now your view should render properly, since you're passing the in-memory #data object attributes as params within the redirect. You then recreate this object in the index page or wherever you wish to redirect to.
To expand on Matt's answer, the reason you're getting NilClass errors is because:
You're redirecting to a data#show action when no show action has been enabled within your routes file. Since you've set your views up for the index, I'm assuming you want to redirect there when the #data object has been verified as valid:
redirect_to data_path
However I would recommend you follow Rails conventions and specify the data#show route within your routes.rb:
resources :data, only: [:index, :new, :create, :show]
and in your data_controller.rb:
def show
#data = Data.find(params[:id])
end
Another problem is that you're not actually saving the #data object upon creating it. The new method populates the attributes, and valid? runs all the validations within the specified context of your defined model and returns true if no errors are found, false otherwise. You want to do something like:
def create
#data = Data.new(data_params)
if #data.save
redirect_to data_path
else
render :new
end
end
Using save attempts to save the record to the database, and runs a validation check anyways - if validation fails the save command will return false, the record will not be saved, and the new template will be re-rendered. If it is saved properly, the controller will redirect to the index page, where you can call upon the particular data object you want and display it within your view.
I have an object that I am trying to allow users to edit in my rails 4 app. The user has_one supp_form and I want them to be able to edit the information in the supp_form. The page is loading fine and the relationships are setup properly.
The error
No route matches [PATCH] "/businesses/3/supp_form/edit"
when I rake routes I see the following route:
edit_business_supp_form_path GET /businesses/:business_id/supp_form/edit(.:format) supp_forms#edit
GET /businesses/:business_id/supp_form(.:format) supp_forms#show
PATCH /businesses/:business_id/supp_form(.:format) supp_forms#update
PUT /businesses/:business_id/supp_form(.:format) supp_forms#update
supp_forms_controller.rb
class SuppFormsController < ApplicationController
before_filter :authenticate_user!
def new
#suppform = SuppForm.new(supp_form_params)
end
def create
#suppform = SuppForm.create(supp_form_params)
end
def edit
#user = User.current_user
#suppform = #user.supp_form
end
def update
#user = current_user
#suppform = SuppForm.update(supp_form_params)
end
private
def supp_form_params
params.require(:supp_form).permit(:id, :business_id, :title, :first_name,
:last_name, :applicant_role, :work_phone_number)
end
end
View
<%= form_for #user.supp_form, :url => edit_business_supp_form_path(#user.supp_form), :html => { :class => "sky-form", :id => "sky-form4" } do |supp_form| %>
<%= supp_form.text_field :work_phone_number, :placeholder => "Your new phone number" %>
<% end %>
The problem is that it tries to access the route using a PATCH request, that is used for updating. In your routes the /businesses/:business_id/supp_form/edit route is only specified for GET requests, thus the error.
This happens because the path you are using in the form points to the edit action (which is only responsible for showing the edit form) and should instead point to the update action. So the route you should be actually using in the is the supp_form_path that, in connection with the PATCH method, pushes the information to the update action, where the object is updated.
I am trying to pass a hidden field from a form whose value is derived from a text blob that user can edit on the webpage. (I use bootstrap-editable to let the user edit the blurb by clicking on it)
Here is the actual workflow:
User goes on 'Invitations page' where they are are provided with a form to enter friends email and shown a default text that will be used in the email
If the user want they can click on the text and edit it. This will make a post call via javascript to update_email method in Invitation controller
After the text is updated user is redirected back so now the user sees the same page with updated text. This works and user sees the updated text blurb instead of default [1-3] can happen any number of times
When the user submits the form , I expect to get the final version of email that I can save in the db and also trigger an email invitation to the users friend
Problem:
I keep getting default text from form parameters. Any idea what I am doing wrong?
Here is the form (Its haml instead of html)
#new-form
= form_for #invitation, :url=> invitations_path(), :html => {:class => 'form-inline', :role => 'form'} do |f|
.form-group
= f.text_field :email, :type=> 'email', :placeholder=> 'Invite your friends via email', :class=> 'form-control invitation-email'
= f.hidden_field :mail_text, :value => #invitation_email
= f.submit :class => 'btn btn-primary submit-email', :value => 'Send'
Here is the invitation controller:
class InvitationsController < ApplicationController
authorize_resource
before_filter :load_invitations, only: [:new, :index]
before_filter :new_invitation, only: [:new, :index]
before_filter :default_email, only: [:index]
#helper_method :default_email
def create
Invitation.create!(email: params[:invitation][:email], invited_by: current_user.id, state: 'sent', mail_text: params[:invitation][:mail_text], url: {referrer_name: current_user.name}.to_param)
redirect_to :back
end
def update_email
#invitation_email = params[:value]
flash[:updated_invitation_email] = params[:value]
redirect_to :back
end
private
def invitation_params
params.require(:invitation).permit!
end
def load_invitations
#invitations ||= current_user.sent_invitations
end
def new_invitation
#invitation = Invitation.new
end
def default_email
default_text = "default text"
#invitation_email = flash[:updated_invitation_email].blank? ? default_text : flash[:updated_invitation_email]
end
end
Assuming you are using Rails 4 then you need to permit the mail_text parameter:
class InvitationsController < ApplicationController
# ...
private
def invitation_params
params.require(:invitation).permit(:email, :mail_text) #...
end
end
Depending on your settings rails strong parameters will either raise an error or just silently null un-permitted params.
I have to say that your flow is a bit weird and that it may be better if you actually use a
more RESTful pattern:
1. User goes on 'Invitations page' where they are are provided with a form to enter friends email and shown a default text that will be used in the email
Send a AJAX POST request to /invitations (InvitationsController#create) it should return a JSON representation of the UNSENT invitation, store the returned invitation id on the form.
Note that you may need to setup the validations on your Invitation model so that it allows :email and :mail_text to be blank on creation
class Invitation < ActiveRecord::Base
validates :email, allow_blank: true
# ...
# Do full validation only when mail is being sent.
with_options if: :is_being_sent? do |invitation|
invitation.validates :email #...
invitation.validates :mail_text #...
end
# ...
def is_being_sent?
changed.include?("state") && state == 'sent'
end
end
2. User edits text
Send a AJAX PUT or PATCH request to /invitations/:id and update the invitation.
3. User clicks send
Send a POST request to /invitations/:id/send. Update the state attribute and validate.
If valid send invitation. Display a message to user.
class InvitationsController < ApplicationController
# ...
# POST /invitations/:id/send
def send
#invitation = Invitation.find(params[:id])
# Ensure we have latest values from form and trigger a more stringent validation
#invitation.update(params.merge({ state: :sent })
if #invitation.valid?
#mail = Invitation.send!
if #mail.delivered?
# display success response
else
# display error
end
else # record is invalid
# redirect to edit
end
end
# ...
end