It's been a while since I've programmed in Rails ... getting up to date with all the Rails 5.0 syntax and changes.
Using Rails 5.0.0.1
Using Ruby ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin16]
I'm trying to setup a simple contact us form on a landing page. I'm going the route of sending the email direct from the form vs. storing it to the database.
I'm using the mail_form gem and following this thread
I know I'm making some rookie mistakes on my controllers but after following several Stack Q/A's I'm still not quite there.
The model is successfully sending email in Rails Console. I just can't get the controller working. This is a one page site so I'm adding partials to the Index page in the Pages View folder.
Error I'm getting
AbstractController::ActionNotFound (The action 'create' could not be found for PagesController):
Routes
Rails.application.routes.draw do
get 'users/new'
resources :pages
root 'pages#index'
end
Form Partial
app/views/pages/_form.html.erb
<%= form_tag(pages_path) do %>
<div class="row">
<div class="column width-6">
<%= text_field_tag 'firstname', nil, class: 'form-element rounded large', placeholder: 'First Name*', tabindex: '1' %>
</div>
<div class="column width-6">
<%= text_field_tag 'lastname', nil, class: 'form-element rounded large', placeholder: 'Last Name*', tabindex: '2' %>
</div>
<div class="column width-6">
<%= email_field_tag 'email', nil, class: 'form-element rounded large', placeholder: 'Email Address*', tabindex: '3' %>
</div>
<div class="column width-6">
<%= text_field_tag 'website', nil, class: 'form-element rounded large', placeholder: 'Website', tabindex: '4' %>
</div>
<div class="column width-6">
<%= text_field_tag 'phone', nil, class: 'form-element rounded large', placeholder: 'Phone', tabindex: '5' %>
</div>
</div>
<div class="row">
<div class="column width-12">
<%= text_area_tag 'message', nil, class: 'form-element rounded large', placeholder: 'Message*', tabindex: '6' %>
</div>
<div class="column width-12">
<%= submit_tag 'Send Email', class: 'form-submit button rounded medium bkg-theme bkg-hover-green color-white color-hover-white' %>
</div>
</div>
<% end %>
Pages Controller
class PagesController < ApplicationController
def index
#contact = Page.new(params[:page])
if #contact.deliver
redirect_to :back, :notice => "Thank you for contacting us, We'll get back to you shortly!"
else
flash.now[:error] = 'Sorry, it looks like there was an error with your message, Please give us a call or shoot us a text at ....'
end
end
end
Thanks for the help. This community is amazing!
Your routes are missing for the pages controller.
in config/routes.rb add:
resources :pages
in PagesController.rb
class PagesController < ApplicationController
def create
#contact = Page.new(params[:page])
if #contact.deliver
redirect_to :back, :notice => "Thank you for contacting us, We'll get back to you shortly!"
else
flash.now[:error] = 'Sorry, it looks like there was an error with your message, Please give us a call or shoot us a text at ....'
end
end
end
which handles AJAX posts.
redirect_to :back is deprecated in rails 5. Instead there is a new function called redirect_back.
But I wouldn't use the index action for creating a new Page, even if you don't save it to the database. Instead I would define a new action called create and redirect to index in the end. As you already use resources :pages in the routes, you don't need to add anything there. Here you find the default routes and their actions, and what they should be used for: http://edgeguides.rubyonrails.org/routing.html#resource-routing-the-rails-default
Also I would consider using form_for instead of form_tag if you're working with a model. Here you find a simple example: http://edgeguides.rubyonrails.org/getting_started.html#the-first-form
I hope this helped a little :)
Related
I'm having an issue very similar to the one asked in this question here: NoMethodError / undefined method `foobar_path' when using form_for However the answer there confuses me.
I went through Michael Hartel's Ruby on Rails tutorial before developing the application I'm working on at the moment, I tried to copy exactly what he did when he created a user model as I created my model. My application is designed to be a database for university professors, so the model I'm using is called "professor" but it's the same concept as "user".
Here is the code for my New.html.erb where is where users go to create a new professor:
<%provide(:title, 'Add a professor') %>
<div class="jumbotron">
<h2> New Professor</h2>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for (#professor) do |f| %>
<%= f.label "First Name" %>
<%= f.text_field :fname %>
<%= f.label "Last Name" %>
<%= f.text_field :lname %>
<%= f.label "School" %>
<%= f.text_field :school %>
<%= f.submit "Add this professor", class: "btn btn-primary" %>
<% end %>
</div>
</div>
</div>
And then here is the code from the Professor_controller.rb
class ProfessorController < ApplicationController
def show
#professor = Professor.find(params[:id])
end
def new
#professor = Professor.new
end
end
When I replace
<%= form_for (#professor) do |f| %>
In new.html.erb with:
<%= form_for (:professor) do |f| %>
It works. The thread I mentioned above said something about adding a route for the controller. My routes.rb looks like this:
Rails.application.routes.draw do
root 'static_pages#home'
get 'about' => 'static_pages#about'
get 'newprof' => 'professor#new'
resources :professor
And I don't believe that in Michael Hartel's book he does anything differently. I'm still very new to Rails so forgive me if this is a bit of an easy question, I've been stuck on it for a few days and I've tried numerous work arounds, using the instance of :professor works but #professor does not and I don't know why.
Within the Rails environment it's very important to be aware of the pluralization requirements of various names. Be sure to declare your resources as plural:
resources :professors
Declaring it in the singular may mess up the automatically generated routes, you'll get thing like professor_path instead of professors_path. You can check what these are with:
rake routes
If you get errors about x_path being missing, check that there's a route with the name x in your routes listing. The most common case is it's mislabeled, a typo, or you've failed to pluralize it properly.
I'm playing with the messenger gem in rails 4.
I have a graph of nodes and I want to be able to bring up a message box (initially in a different page but will make it a partial later) when a node is pressed so that the current user can message that node.
The id for the clicked node is kept in a div called NameID
At the moment all I've got working is a button that opens the new message page and then you can choose a user from a drop down list. I guess I want that drop down list- the recipient- to be prepopulated from the currently clicked node on the index page.
Here is what I have so far:
index.html.erb
<p><a class="btn btn-lg btn-primary" id="BtnMessageNode" href="/messages/new">Start conversation</a></p>
<div id=NameID><<THIS IS POPULATED BY JAVASCRIPT>></div>
messages_controller.rb
class MessagesController < ApplicationController
before_action :authenticate_user!
def new
#chosen_recipient = User.find_by(id: params[:to].to_i) if params[:to]
end
def create
recipients = User.where(id: params['recipients'])
conversation = current_user.send_message(recipients, params[:message][:body], params[:message][:subject]).conversation
flash[:success] = "Message has been sent!"
redirect_to conversation_path(conversation)
end
end
helpers/messages_helper.rb
module MessagesHelper
def recipients_options(chosen_recipient = nil)
s = ''
User.all.each do |user|
s << "<option value='#{user.id}' data-img-src='#{gravatar_image_url(user.email, size: 50)}' #{'selected' if user == chosen_recipient}>#{user.name}</option>"
end
s.html_safe
end
end
messages/new.html.erb
<% page_header "Start Conversation" %>
<%= form_tag messages_path, method: :post do %>
<div class="form-group">
<%= label_tag 'message[subject]', 'Subject' %>
<%= text_field_tag 'message[subject]', nil, class: 'form-control', required: true %>
</div>
<div class="form-group">
<%= label_tag 'message[body]', 'Message' %>
<%= text_area_tag 'message[body]', nil, cols: 3, class: 'form-control', required: true %>
</div>
<div class="form-group">
<%= label_tag 'recipients', 'Choose recipients' %>
<%= select_tag 'recipients', recipients_options(#chosen_recipient), multiple: true, class: 'form-control chosen-it' %>
</div>
<%= submit_tag 'Send', class: 'btn btn-primary' %>
<% end %>
There are basically two ways to pass parameters to GET routes:
A. Named segments
/users/:user_id/message/new
This nested route would be great if you are sending a message to a single user.
B. Query parameters
Rails supports query parameters as well:
/message/new?to=2
Rails automatically adds query parameters to the params hash. So in this case you would do params[:to].
You can use the Rails route helpers so that you don't have to deal with encoding urls yourself:
new_message_path(to: #user.id)
Use query params for optional parameters like filters and sorting or in this case a preset. Don't use them like users?id=5.
I am using elasticsearch on my rails 4 app to search through my articles.
However, when an article is not found it redirects to a page where it alerts the user that no results are found, and allows to request a page. Instead of it saying "no results found" I want it to say "no results for ______ found" in which is takes the search bar query.
I have defined a method in the articles_controller in order to get the query but it won't show up on the page since the "no results page" uses a different controller.
What would be the best way to pull the method onto another controller or view in this case? Having trouble finding a straight forward answer for what I am trying to do. Thank you very much.
articles_controller:
def index
if params[:query].present?
#articles = Article.search(params[:query], misspellings: {edit_distance: 1})
else
#articles = Article.all
end
if #articles.blank?
return redirect_to request_path
end
get_query
end
private
def get_query
#userquery = params[:query]
end
new.html.erb (view for "no results found" page. Uses a different controller than articles page):
<body class="contactrequest">
<div class="authform" style="margin-top:15px">
<%= simple_form_for #request, :url => request_path do |f| %>
<h3 style = "text-align:center; color:red;">No results found. <%= #userquery %></h3>
<h1 style = "text-align:center; color:black;">Request a Page</h1>
<h5 style = "text-align:center; color:black; margin-bottom: 25px;">Our experts will gather the information,<br> and have your page us ASAP!</h5>
<%= f.error_notification %>
<div class="form-group">
<%= f.text_field :email, placeholder: 'Email', :autofocus => true, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.text_field :subject, placeholder: 'Item / Page Requested', class: 'form-control' %>
</div>
<div class="form-group">
<%= f.text_area :content, placeholder: 'Any additional details...', class: 'form-control', :rows => '5' %>
</div>
<%= f.submit 'Request it', :class => 'btn btn-lg btn-danger btn-block' %>
<% end %>
As you can see I've tried calling that #userquery method to display on the view page, but it doesn't show up since it's defined on a different controller. Any recommendations would be awesome.
I would suggest you render results and no results from the same controller/view. A nice clean way to do this is with partials. Your view could look something like:
<% if #articles.blank? %>
<%= render 'no_results' %>
<% else %>
<%= render 'results' %>
<% end %>
Then, you would simply create _no_results.html.erb and populate it with your current new.html.erb contents and do the same for your nominal results page (with partial _results.html.erb).
I'm working on a Rails 4 web application, using Devise and CanCanCan.
When a user first signs up to create an account, they are redirected to a subscription page where they enter in credit card details, etc.
User Creation -> Subscription Creation = Form works
This is working absolutely perfectly and once they enter in their subscription information, a permission change is made on their account and they can then access a new part of the site. All good.
Now the issue I am having is, if a user signs up, then tries to access this new part of the site without subscribing, I redirect them to the subscription page. However when I do this, the form just doesn't work. They hit submit and nothing happens.
User Creation -> Tries to access resource, gets redirected to
Subscription Creation = Form doesn't work
Here is the code I am using to perform the redirection:
application_controller.rb
def access_denied(exception)
redirect_to(new_subscription_path, alert: exception.message + " Please subscribe.")
end
The strange thing is that I am using the exact same code to redirect when they first create a user account. This is shown here:
registrations_controller.rb
def after_sign_up_path_for(resource)
new_subscription_path
end
Here is the code for the subscription controller:
class SubscriptionsController < ApplicationController
before_filter :authenticate_user!
def new
#subscription = Subscription.new
end
def create
#subscription = Subscription.new(subscription_params)
#user = current_user
#subscription.user_id = current_user.id
if #subscription.save_with_payment
redirect_to success_path, :notice => "Thank you for subscribing!"
if current_user.role = "guest"
User.update(current_user.id, role: "read")
end
UserMailer.subscription_welcome_email(#user).deliver
else
render :new
end
end
def show
#subscription = Subscription.find(params[:id])
end
def destroy
#subscription = Subscription.find_by(user_id: current_user.id)
User.update(current_user.id, role: "guest")
unless #subscription.stripe_customer_id.nil?
customer = Stripe::Customer.retrieve(#subscription.stripe_customer_id)
customer.subscriptions.retrieve(customer.subscriptions.first.id).delete
end
#user = current_user
UserMailer.subscription_destroy_email(#user).deliver
#subscription.destroy
rescue Stripe::StripeError => e
logger.error "Stripe Error: " + e.message
errors.add :base, "Unable to cancel your subscription. #{e.message}."
false
end
def subscription_params
params.require(:subscription).permit(:stripe_card_token, :last_4_digits, :plan, :expiry_month, :expiry_year)
end
end
Form code:
<div class='panel panel-default'>
<div class='panel-heading'>
<h2>Subscribe</h2>
</div>
<div class='panel-body'>
<%= semantic_form_for #subscription, :html => {:class => 'main-form'} do |f| %>
<font color=red><b><%= f.semantic_errors *f.object.errors.keys %></b></font>
<%= f.hidden_field :stripe_card_token %>
<div id='stripe_error' class="alert alert-info" style='display:none'>
</div>
<span class="help-block">Nothing is billed to your card for 7 days. <b>Guaranteed. </b>
<br>If you choose to continue after 7 days, only then will you be billed.</span>
<div class='form-group'>
<%= label_tag :card_number, "Credit Card Number" %><%= image_tag "welcome/checkout/amex.png", alt: "American Express", class: "credit-card-image" %><%= image_tag "welcome/checkout/mastercard.png", alt: "Mastercard", class: "credit-card-image" %><%= image_tag "welcome/checkout/visa.png", alt: "Visa", class: "credit-card-image" %>
<%= text_field_tag :card_number, nil, name: nil, class: 'form-control input-box', :placeholder => 'Credit Card Number' %>
</div>
<div class='row'>
<div class="col-xs-6">
<%= label_tag :card_code, "Security Code on Card (CVC)" %><%= image_tag "welcome/checkout/credit.png", alt: "Credit Card Image", class: "credit-card-image" %>
<%= text_field_tag :card_code, nil, name: nil, class: 'form-control input-box', :placeholder => 'Security Code on Card (CVC)' %>
</div>
<div class="col-xs-6">
<%= label_tag :card_month, "Card Expiration" %><br>
<%= select_month nil, {add_month_numbers: true}, {name: nil, id: "card_month", class: 'expiration'} %>
<%= select_year nil, {start_year: Date.today.year+1, end_year: Date.today.year+15}, {name: nil, id: "card_year", class: 'expiration'} %>
</div>
</div>
</div>
<div id="stripe_error">
<noscript>JavaScript is not enabled and is required for this form. First enable it in your web browser settings.</noscript>
</div>
<div>
<%= f.submit "Subscribe", class: 'btn standard-button' %>
</div>
<% end %>
</div>
</div>
Can anyone assist? Let me know if any extra code is required. Thanks
EDIT: Just to make things weird, this error is only happening when I hit a link in my navigation that is new_subscription_path .. the access denied works fine if I type in manually the URL of the permissioned resource. Could there be something wrong with the path I am using in the header? Do I need to pass something specific into it? I've also tried to check if it was JavaScript by adding in a console log, but nothing comes through, so I don't think this is an issue, despite it feeling like a JS issue.
You should check you javascript. Clearly it blocks form from submission. I've looked at your previous question here and it looks like your handleStripeResponse handler always goes into else condition block not submitting form as the result. My bet is that $('meta[name="stripe-key"]').attr('content') is undefined after your redirection.
Disabled Turbolinks solved this problem
The -Form_html.erb, the routes.rb and the create method in the controller are as below. But on form submission, it gives nil class error the moment I use params[:mail_setting]
routes.rb
-----------
resources :mail_settings
the _form.html.erb
---------
<%= form_tag '/mail_settings' do %>
<div class="fieldBlock">
<%= label_tag :name %> <%= text_field_tag :name%> </div>
<div class="fieldBlock">
<%= label_tag :id%> <%= text_field_tag :id%> </div>
<div class="actions fieldBlock">
<%= submit_tag "Update Settings ", :class => "btn-large btn-success" %>
</div>
<% end %>
The create method in controller:
def create
#mail_setting = MailSetting.find_by_user_id_and_name(current_user.id, params[:mail_setting][:name])
if ! #mail_setting.blank?
#mail_setting.update_attributes(params[:mail_setting])
else
#mail_setting = MailSetting.new(params[:mail_setting])
#mail_setting.save
render action: "index"
end
end
Try using params[:mailsetting] without the underscore. The model is named MailSetting, so I assume that would be right. The NoMethod error means that there is no generated helper method by the name of mail_setting, which, since you already made the model, is probably because it's spelled wrong.
I would recommend not using underscores/dashes when naming your resources anyways since it just confuses the grammar.