undefined method `[]' for nil:NilClass railstutorial.org 8.20 > - ruby-on-rails-4

I'm following the rails-tutorials from Michael Hartl, it's really fun !
but i'm having troubles from upon listing 8.20 and so on.
Cause i guessed i had made a type-o i erased the app and started from scratch again..
The best way to learn is repeat right ?
Well.. also on the second build i got the same error.
> NoMethodError in SessionsController#create
undefined method `[]' for nil:NilClass
Extracted source (around line #7):
6 def create
7 user = User.find_by(email: params[:session][:email].downcase)
8 if user && user.authenticate(params[:session][:password])
9 sign_in user
10 else
after googling for a few hours i tried resetting the db ( drop / create / migrate test:prepare)
i have tried copying pieces of code out of the example (e.g. controllers/helpers/views)
but I cant seem to find the solution.
Here is the code for
session_controller:
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
sign_in user
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
end
end
session helper:
module SessionsHelper
def sign_in(user)
remember_token = User.new_remember_token
cookies.permanent[:remember_token] = remember_token
user.update_attribute(:remember_token, User.encrypt(remember_token))
self.current_user = user
end
def signed_in?
!current_user.nil?
end
def current_user=(user)
#current_user = user
end
def current_user
remember_token = User.encrypt(cookies[:remember_token])
#current_user ||= User.find_by(remember_token: remember_token)
end
def current_user?(user)
user == current_user
end
def sign_out
current_user.update_attribute(:remember_token,
User.encrypt(User.new_remember_token))
cookies.delete(:remember_token)
self.current_user = nil
end
end
User model
class User < ActiveRecord::Base
before_save {self.email = email.downcase }
before_create :create_remember_token
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX},
uniqueness: {case_sensetive: false}
has_secure_password
validates :password, length: { minimum: 3 }
def User.new_remember_token
SecureRandom.urlsafe_base64
# SecureRandom.urlsafe_base64
end
def User.encrypt(token)
Digest::SHA1.hexdigest(token.to_s)
end
private
def create_remember_token
self.remember_token = User.encrypt(User.new_remember_token)
end
end
user controller
class UsersController < ApplicationController
def new
#user = User.new
end
def show
#user = User.find(params[:id])
end
def create
#user = User.new(user_params)
if #user.save
flash.now[:succes] = "Welcome to the sample app"
redirect_to #user
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
end
and the user helper
module UsersHelper
# Returns the Gravatar (http://gravatar.com/) for the given user.
def gravatar_for(user, options = { size: 50 })
gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
size = options[:size]
gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}?s=#{size}"
image_tag(gravatar_url, alt: user.name, class: "gravatar")
end
end
how can i properly copy-paste the error log ?

Based on the error you're getting, the problem is clearly somewhere in your Users controller:
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
sign_in user
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'
end
end
The error is being generated because params[:session] is, in fact, nil. Now the question is, why?
My guess is that you have a typo in your sign_in form, it should be:
<%= form_for(:session, url: sessions_path) do |f| %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.submit "Sign in", class: "btn btn-large btn-primary" %>
<% end %>
Please make sure :session is typed correctly.

Related

rails 4 semantic ui multi-select show user selections on edit

I am trying to implement multi-select in a form in rails 4, using Semantic UI. I want users to be able to select multiple categories for each post. So far, I am able to display the dropdown select field which pulls all the categories from the database as follows:
<%= form_for #post, :html => {:class => "ui form bk-form group"} do |f| %>
<label>Post title:</label><br />
<%= f.text_field :title, autofocus: true %>
<label>Choose a category:</label><br />
<%= f.select(:category_ids,options_for_select(Category.all.collect{|x| [x.name,x.id,class:'item']}),{prompt:'Select categories'}, multiple: true, class:'ui fluid dropdown selection multiple')%>
<% end %>
With this, I am able to create and save posts and the data is inserted in the database. However, when I try to edit an article, the pre-selected categories do not show. I have tried to set the value: #post.categories option in the select field and still cannot get the existing categories to show. Thanks in advance for your thoughts.
UPDATED
Models are as follows:
class Post < ActiveRecord::Base
has_many :post_categories
has_many :categories, through: :post_categories
end
class Category < ActiveRecord::Base
has_many :post_categories
has_many :posts, through: :post_categories
end
class PostCategory < ActiveRecord::Base
belongs_to :post
belongs_to :category, :counter_cache => :posts_count
end
Then my posts_controller.rb
class PostsController < ApplicationController
before_action :set_post, only: [:edit, :update, :show]
def index
#posts = Post.all
end
def new
end
def create
#post = Post.new(post_params)
#post.user = current_user
if #post.save
flash[:notice] = "Post was successfully created"
redirect_to user_posts_path
else
flash[:alert] = "Oh Snap!! We could not save your post"
render 'new'
end
end
def edit
end
def update
if #post.update(post_params)
flash[:notice] = "Post was successfully updated"
redirect_to user_posts_path
else
flash[:alert] = "Oh Snap!! We could not update your post"
render 'edit'
end
end
private
def post_params
params.require(:post).permit(:title, :description, :published, :tag_list, category_ids: [])
end
def set_post
#post = Post.find(params[:id])
end
end

About validation in rails 4

I got problem in validation with modal popup. This is my index.html.haml:
.container-index
%h1 All Posts Here
%button.btn.btn-info(type="button" data-toggle="modal" data-target="#myModal") New Post
= render 'form'
- #posts.each do |post|
.col-md-4
%h3= link_to post.title,post
%p= post.content
= "#{time_ago_in_words post.created_at} ago "
_form.html.haml:
.container
= simple_form_for current_user.posts.build do |f|
%div.modal.fade#myModal(tabindex="-1" role="dialog" aria-labelledby="myModalLabel")
%div.modal-dialog(role="document")
%div.modal-content
%div.modal-header
%button.close(type="button" data-dismiss="modal" aria-label="Close")
%span(aria-hidden="true") ×
%h3.modal-title#myModalLabel New Post
%div.modal-body
= f.input :title, label:"Title",class:'form-group',name: 'title'
= f.input :content, label:'Content',class:'form-group',name:'content'
%div.modal-footer
%button.btn.btn-danger#mynewpostclose(type="button" data-dismiss="modal") Close
= f.submit 'Create', class:"btn btn-primary"
post.rb:
validates :title, presence: true
validates :content, presence: true
posts_controller.rb:
before_action :find_post, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
#posts = Post.all.order("created_at DESC")
end
def new
#post = current_user.posts.build
end
def create
#post = current_user.posts.build(post_params)
if #post.save
redirect_to #post, notice: 'Created Successfully'
else
render 'new'
end
end
def show
end
def edit
end
def update
if #post.update(post_params)
redirect_to #post, notice: 'Updated Successfully'
else
render 'edit'
end
end
def destroy
#post.destroy
redirect_to posts_path(#post), notice: 'Deleted Successfully'
end
private
def find_post
#post = Post.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :content)
end
I do not know how to show up the warningWhen I create a new post without any title or contentit'll link to a blank page and don't create any new postI just wanna call warning inside modal when submit, anyone can help me,plzz?
In your form you need to replace this line
= simple_form_for current_user.posts.build do |f|
with this;
= simple_form_for #post do |f|
This way, when your create action renders the new template, the form will be given the instance of Post which failed to save allowing simple form to display the error messages.

Ruby on Rails 4: Deleting user triggers error

Whenever I try to delete a user I get the error: Couldn't find User with 'id'=8. The error points to a line from application_controller.rb in the "current_user" method: ActiveRecord::RecordNotFound at /users. "/users" is where I'm trying to redirect_to.
I don't know where I'm going wrong. I wonder if it's a <%= javascript_include_tag ... %> that I'm missing in the application.html.erb file.
application_controller.rb
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
users_controller.rb
def delete
#user = User.find(params[:id])
end
def destroy
#user = User.find(params[:id]).destroy
flash[:warning] = '#{#user.name} has been deleted.'
redirect_to users_path
end
sessions_controller.rb
class SessionsController < ApplicationController
def create
user = User.find_by(email: params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
if request.referrer == login_url
redirect_to root_path
else
redirect_to :back
end
else
flash.now[:danger] = "Email and password did not match. Please try again."
render :new
end
end
def destroy
session[:user_id] = nil
flash[:success] = "Logged out."
redirect_to :back
end
end
views/users/show.html.erb
<p id="notice"><%= notice %></p>
<h2 id="page-title"><%= #user.name %> <small>#<%= #user.username %></small>
<div class="small pull-right"></div>
</h2>
<hr/>
<% #user.types.each do |type| %>
<h4><small><%= type.name %></small></h4>
<% end %>
<% if current_user == #user %> # visible to current_user
<div class="float-right">
<%= link_to 'Edit', edit_user_path(#user), class: 'btn btn-default' %>
<%= link_to 'Delete Account', user_path,
data: { confirm: 'Are you sure you want to delete your account forever?' },
method: :delete, class: 'btn btn-danger' %>
</div>
<% end %>
If you need anymore files let me know.
I feel like this is a simple fix. Please help. And thank you in advance!
When you use find with a non existing record id, ActiveRecord throws ActiveRecord::RecordNotFound exception. You can get around this by usingfind_by, which will return nil. so try this in your application_controller.rb
def current_user
#current_user ||= User.find_by(id: session[:user_id])
end
Or you can just use your check more correctly by doing this
def current_user
#current_user ||= (session[:user_id].present? && User.find(session[:user_id]))
end
The second will still raise exception if the user_id in the session is not an invalid user.
Hope that helps
I guess if bug is in application controller add the following code in the destroy method of user controller:
session[:user_id] = nil if current_user == #user
This way if you delete the current connected user, it'll be logged out.

How can I fix 404 page while trying to authenticate user with omniauth-github?

Everytime I click the "Sign in with Github" button, I get a Page not found. When I try http://127.0.0.1:3000/auth/github/callback
I get an error called OmniAuth::Strategies::OAuth2::CallbackError which says "csrf_detected | CSRF detected" . Here is my code:
initializers/omniauth.rb:
OmniAuth.config.logger = Rails.logger
Rails.application.config.middleware.use OmniAuth::Builder do
provider :github, ENV['GITHUB_ID'], ENV['GITHUB_SECRET'],
:scope => 'user,public_repo',
:redirect_uri => ENV['http://127.0.0.1:3000']
end
routes.rb:
root 'users#new'
get '/auth/:provider/callback' => 'sessions#create'
get '/signout' => 'sessions#destroy', as: :signout
end
views/users/new.html.erb:
<% if current_user %>
<h1> Welcome: </h1>
<h2><%= link_to 'Sign out', signout_path %></h2>
<% else %>
<h2><%= link_to 'Sign in with Github', "/auth/github" %></h2>
<% end %>
sessions_controller.rb:
class SessionsController < ApplicationController
def new
end
def create
auth = request.env["omniauth.auth"]
user = User.where(:provider => auth['provider'], :uid => auth['uid'].to_s).first || User.from_omniauth(auth)
reset_session
session[:user_id] = user.id
redirect_to root_url, :notice => "Signed in!"
end
def destroy
session[:user_id] = nil
redirect_to root_url, :notice => 'Signed out!'
end
def failure
redirect_to root_url, :alert => "Authentication error: #{params[:message].humanize}"
end
end
user.rb:
class User < ActiveRecord::Base
def self.from_omniauth(auth)
# where(auth.slice(:provider, :uid)).first_or_initialize.tap
create! do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.save!
end
end
end
application_controller.rb:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
helper_method :current_user
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
end
Please help!
I managed to fix this error by adding scope: 'user:email' to the end of the provider statement in the OmniAuth initializer file.
Rails.application.config.middleware.use OmniAuth::Builder do
provider :github, ENV['GITHUB_KEY'], ENV['GITHUB_SECRET'], scope: 'user:email'
end
Error 404 means "File or Directory not found". In other words, the server received and understood your request, and would have been quite willing to fulfil the request, but the data that you asked for doesn't exist.

Nested attributes - Unpermitted parameters Rails 4

There is a lot of resources on SO about issues on Nested attributes in Rails 4 regarding strong parameters but I don't find any solution on this: (so sorry if it's a duplicate)
I have a 1-1 relation between member and profile.
When trying to update a member with profile attributes I've got this error:
Unpermitted parameters: profile
Where are my params
===> params: {"member"=>{"profile"=>{"first_name"=>"test", "last_name"=>"test"}, "email"=>"test#test.com"}}
My models:
Member.rb
class Member < ActiveRecord::Base
...
has_one :profile
accepts_nested_attributes_for :profile
end
Profile.rb
class Profile < ActiveRecord::Base
belongs_to :member
end
My form:
edit.html.slim
= simple_form_for [:admin, #member] do |f|
= f.simple_fields_for #member.profile do |pf|
= pf.input :first_name
= pf.input :last_name
= f.input :email
= f.button :submit
and my controller:
admin/members_controller.rb
class Admin::MembersController < Admin::BaseController
before_action :set_member, only: [:edit]
def edit
end
def update
if #member.update(member_params)
Rails.logger.debug "===> (1)"
redirect_to edit_admin_member_path
else
render action: 'edit'
end
end
private
def set_member
#member = Member.find(params[:id])
end
def member_params
params[:member].permit(:email, profile_attributes: [:first_name, :last_name ])
end
end
I've tried many things but don't understand where is my mistake.. Moreover in the update method it says the #member is correctly updated (shown ===> (1))
Ok get it..
I think this is caused by simple_form:
= simple_form_for [:admin, #member] do |f|
= f.simple_fields_for :profile, #member.profile do |pf|
= pf.input :first_name
= pf.input :last_name
= f.input :email
= f.button :submit
Try Adding the :member_id inside profile_attributes which is in member_params
so it will look like this:
def member_params
params[:member].permit(:email, profile_attributes: [:first_name, :last_name, :member_id ])
end