Rails 4: scroll browser window to form after failed submission (validation errors) - forms

So I have form (typical articles and comments example) for comments at bottom of page. If validation fails I display validation errors.
Thats my comments controller code:
class CommentsController < ApplicationController
before_action :authenticate_admin!, only: [:destroy]
expose(:article)
expose(:comment, attributes: :comment_params)
expose(:reply) { Reply.new }
def create
comment.article = article
if verify_recaptcha(model: comment, message: t('captcha_verification_error')) && comment.save
flash[:comment_notice] = t('comment_created_successfully')
redirect_to article_path(article) + '#comments'
else
flash[:comment_errors] = comment.errors.full_messages
render 'articles/show'
end
end
def destroy
comment.destroy
redirect_to article_path(article)
end
private
def comment_params
params.require(:comment).permit(:author, :content)
end
end
Here is form:
= simple_form_for(comment, url: article_comments_path(article)) do |f|
- if flash[:comment_errors]
.alert.alert-danger
strong= pluralize(flash[:comment_errors].count, 'error') + ' prohibited this article from being saved:'
- flash[:comment_errors].each do |msg|
ul
li= msg
fieldset class='form-group'
= f.label t('author')
= f.text_field :author, class: 'form-control', placeholder: t('who_are_you')
fieldset class='form-group'
= f.label t('content')
= f.text_area :content, class: 'form-control', rows: 6, placeholder: t('what_do_you_want_to_say')
fieldset class='form-group'
= recaptcha_tags
fieldset class='form-group'
= f.submit t('create_comment'), class: 'btn btn-primary'
For forms I'm using simple-form. Also I'm using decent exposure and slim
I want my page to scroll down to form after validation fails (So user don't have to scroll manually). Is there simple way to achieve that?
AFAIK I can't pass anchor to render (That would solve problem). Any ideas?

So I solved it with this javascript placed in comment form:
javascript:
if (document.getElementById("comment_errors")) {
location.hash = '#new_comment';
}
When element with id 'comment_errors' (My validation errors div) exists it jumps to it.

Related

How do I pass form variables from views to controllers in Rails 4?

I'm trying to accept telephone numbers in a simple form and I can't seem to get it to pass the variable through to the controller. The code I have so far is:
view on /users/new.erb:
<%= form_for #user do |f| %>
<%= field_set_tag do %>
<p><%= f.label :phone %><br>
<%= f.text_field :phone%>
<%= f.submit "Submit" %>
<% end %>
<% end %>
and in the controller I have:
def new
#user = User.new
end
def create
#user = User.new(params[:new])
phone = #user.phone
end
Any help would be greatly appreciated. Thanks.
There are a few problems with your code. When you write:
<%= form_for #user %>
All the form fields are sent to the controller in the form of a hash with "user" as the root. Just like
{"user": {"phone": "ENTERED PHONE NUMBER"}}
To access these fields in the controller you need to use the following method:
#phone_number = params[:user][:phone]
One More Important Thing
For security purposes rails does uses Strong Parameters. It means that you can't use the form parameters directly in Active Model for mass assignment like this:
#user = User.new(params[:user])
You need to permit all the fields explicitly for mass assignment. This can be achieved as follows.
def create
#user = User.new(params_user)
#user.save
end
private
def params_user
params.require(:user).permit(:phone)
end
params[:new] just passes the parameter :new to your #user object, but there is no params[:new] parameter because it is not defined in your form. params[:phone] should be passed to '#user' just params if you want all available params that were submitted.
Try
#user = User.new(params) #instead of #user = User.new(params[:new])
#user.phone

Call method after submitting form Rails

I have the following model:
class Coupon < ActiveRecord::Base
belongs_to :company
validates :description, presence: true, length: { maximum: 50 }, uniqueness: { case_sensitive: false }
validates :fine_print, presence: true
end
and the following method in the coupon controller:
def redeem
if params[:pin] == #coupon.company.pin
redirect_to root_path
else
flash.now[:notice] = "Incorrect Pin"
render :show
end
end
This form is in the a view:
<%= form_for( #coupon, :url => coupons_redeem_path( #coupon ), :html => { :method => :post } ) do |f| %>
<%= label_tag("pin", "Search for:") %>
<%= text_field_tag("pin") %>
<%= f.submit "Close Message" %>
<% end %>
I want the form to call the redeem method in the coupons controller when hitting submit but am getting this error:
No route matches [POST] "/coupons/redeem.1"
EDIT
These are my routes:
resources :companies do
resources :coupons
end
get 'coupons/redeem'
In your routes, coupons are nested resources of companies. So you should choose one of these alternatives:
1st:
resources :companies do
resources :coupons do
post :redeem, on: :member
end
end
This leads to helpers like this: redeem_company_coupon_path(company, coupon) (and send smth there via POST).
If you don't want to include company to your path, you could choose 2nd:
resources :companies do
resources :coupons
end
post 'coupons/:id/redeem', to: 'coupons#redeem', as: :redeem_coupon
After that you could use redeem_coupon_path(coupon) helper

Rails Tutorial 3.2 Chapter 8 error: NoMethodError in SessionsController#create

I'm going through the rails tutorial and my login page is throwing an exception after exercise 8.1.5 when I click the login button with no email or pw entered:
http://ruby.railstutorial.org/chapters/sign-in-sign-out#sec-rendering_with_a_flash_message
Error:
NoMethodError in SessionsController#create
undefined method `[]' for nil:NilClass
app/controllers/sessions_controller.rb:7:in `create'
SessionsController matches the final code exactly for the Create method
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:session][:email].downcase) #line 7
if user && User.authenticate(params[:session][:password])
#will fill this in later
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
end
end
I did change the button label to Log in instead of "Sign in" as that is too confusing with "Sign up", but I didn't think that would create the problem. sessions\new.html.erb
<% provide(:title, "Log in") %>
<h1>Log in</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(:sesssion, url: sessions_path) do |f| %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.submit "Log in", class: "btn btn-large btn-primary" %>
<% end %>
<p>New user? <%= link_to "Sign up now!", signup_path %></p>
</div>
</div>
This post hints that I need a method in my user model, but adding that didn't help:
NoMethodError in SessionsController#create
I tried adding this to user.rb, but it didn't help
results from find_by_email executed in function differs from console:
def self.authenticate(email, submitted_password)
user = find_by_email(email)
return user.nil? ? nil : user
end
Any ideas would be greatly appreciated!
I've looked at the example from the book and your code and I noticed this line
if user && User.authenticate(params[:session][:password])
your User.authenticate should be lowercased to user.authenticate. Revert back to your original code.
I have just had the same problem and found that in fact i needed [:sessions] with an s on the end!
So line reads
if user && User.authenticate(params[:sessions][:password])
Hope this helps someone in the future!
I had the same problem after doing exercise 1 in chapter 8 where I replaced the use of form_for with form_tag. This resulted in the name attributes in the generated input form fields changing from name="session[email]" and name="session[password]" to name="email" and name="password". Subsequently, I needed to access the params using params[:email] and params[:password] instead of params[:session][:email] and params[:session][:password].
My new Sessions controller looks like this:
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:email].downcase)
if user && user.authenticate(params[:password])
sign_in user
redirect_to user
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
sign_out
redirect_to root_url
end
end
This solved the problem for me. Hope this is helpful to someone else.
In this section from the tutorial chapter 8, all instances of [:session] should be [:sessions]. Hope that helps.
class SessionsController < ApplicationController
.
.
.
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
sign_in user
redirect_to user
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'
end
end
.
.
.
end
Could you confirm the word 'session' in app/view/session/new.html.erb spelling correct?
I see you wrote:
form_for(:sesssion, url: sessions_path) do |f|
But in app/controllers/sessions_controller.rb, you wrote:
user = User.find_by_email(params[:session][:email].downcase) #line 7
They must be the same.

Save the file manually using paperclip from the params, without scaffold

I am new to rails, I was working on paperclip gem and wanted to save the simple files, saved from paperclip.
I have the My model as follow :-
class UserAttachment < ActiveRecord::Base
attr_accessible :email, :user_id, :attached_file
has_attached_file :attached_file
validates_attachment_presence :attached_file
validates_attachment_size :attached_file, :less_than => 20.megabytes
end
My controller action where the form is called :-
class HomeController < ApplicationController
def index
#uattachment = UserAttachment.new
end
end
Index view code, where the form is located
<%= form_for #uattachment, :url => attachment_get_link_path, :html => { :method => :post, :id => 'attachment_form', :multipart => true }, :remote => true do |f| %>
<%= f.email_field :email, :value=>nil, :placeholder => "Enter your email here", :required => true %><br />
<%= f.file_field :attached_file %>
<%= f.submit "Submit" %>
<% end %>
I want to use some following kind of code to save the data :-
(Code below is not the correct code, it's an excitation to tell what I want to do in my application.)
#uattachment = UserAttachment.new
#uattachment = params[:user_attachment]
#uattachment.save
Params received are as follows :-
(rdb:6) pp params
{"utf8"=>"✓",
"authenticity_token"=>"dfjaskldjadslgjsoidruts48589034lsker=",
"user_attachment"=>
{"email"=>"testing#email.com",
"attached_file"=>
#<ActionDispatch::Http::UploadedFile:0x007fcb58682ba0
#content_type="image/jpeg",
#headers=
"Content-Disposition: form-data; name=\"user_attachment[attached_file]\"; filename=\"someimage.jpg\"\r\nContent-Type: image/jpeg\r\n",
#original_filename="800px-Kinnaur_Kailash.jpg",
#tempfile=#<File:/tmp/RackMultipart20121205-8432-1fc1kpi>>},
"commit"=>"Submit",
"controller"=>"attachment",
"action"=>"get_link"}
Got the catch, it was pretty simple, I checked it from the scaffolded assignment,
def index
#uattachment = UserAttachment.new(params[:user_attachment])
#uattachment.save
end
And you get the golden words in response "true".

how do I generate a tag cloud in acts_as_taggable_on?

I can't debug why I am getting an error:
class VendorsController < ApplicationController
def tag_cloud
#tags = Vendor.tag_counts_on(:tags)
end
I set this class as Taggable:
class Vendor < ActiveRecord::Base
acts_as_taggable_on :tags, :competitors
I include the TagsHelper:
module VendorsHelper
include TagsHelper
end
This is in my View:
<% tag_cloud(#tags, %w(css1 css2 css3 css4)) do |tag, css_class| %>
<%= link_to tag.name, { :action => :tag, :id => tag.name }, :class => css_class %>
<% end %>
This is the error that I get:
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.empty?
Each instance of Vendor has at least one Tag.
Got it, I needed to add: #tags = Vendor.tag_counts_on(:tags) in the index controller.