undefined method `scard' for nil:NilClass - ruby-on-rails

app/models/user.rb:51:in `cart_count'
app/views/layouts/_header.html.erb:24:in `block in _app_views_layouts__header_html_erb__3312865121531214569_70179387150260'
app/views/layouts/_header.html.erb:23:in `_app_views_layouts__header_html_erb__3312865121531214569_70179387150260'
app/views/users/show.html.erb:40:in `_app_views_users_show_html_erb___592785710009336321_70179415740600'
When I attempt to view page after identification, I get the error above.
Here's my layouts/header.html.erb code:
<% if signed_in? %>
<%= link_to accueilconnect_path do%>
<li class="forma">Accueil</li>
<% end %>
<%= link_to nosformations_path do%>
<li class="contac">Formations</li>
<% end %>
<%= link_to devenirformateur_path do%>
<li class="contac">Devenir formateur</li>
<% end %>
<%= link_to contacts_path do%>
<li class="contac">Contact</li>
<% end %>
<%= link_to cart_path do%>
<i class="fi-shopping-cart"></i> My Cart (<span class="cart-count"><%=current_user.cart_count%></span>)
<%end%>
<%= link_to image_tag('user2.png', :class => "user_icon"), current_user %>
<% end %>
and here is my User Model :
class User < ActiveRecord::Base
attr_accessor :password
before_save { self.email = email.downcase }
attr_accessible :name, :email, :login, :password, :password_confirmation
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :name, :presence => true,
:length => { :maximum => 50 }
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
validates :login, :presence => true,
:length => { :maximum => 20 }
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
before_create :confirmation_token
before_create :encrypt_password
# Retour true (vrai) si le mot de passe correspond.
def has_password?(password_soumis)
encrypted_password == encrypt(password_soumis)
# Compare encrypted_password avec la version cryptée de
# password_soumis.
end
def authenticate(submitted_password)
self.has_password?(submitted_password)
end
def self.authenticate_with_salt(id, cookie_salt)
user = find_by_id(id)
(user && user.salt == cookie_salt) ? user : nil
end
def email_activate
self.email_confirmed = true
self.confirm_token = nil
save!(:validate => false)
end
def cart_count
$redis.scard "cart#{id}"
end
private
def encrypt_password
self.salt = make_salt if new_record?
self.encrypted_password = encrypt(password)
end
def encrypt(string)
secure_hash("#{salt}--#{string}")
end
def make_salt
secure_hash("#{Time.now.utc}--#{password}")
end
def secure_hash(string)
Digest::SHA2.hexdigest(string)
end
def confirmation_token
if self.confirm_token.blank?
self.confirm_token = SecureRandom.urlsafe_base64.to_s
end
end
end
problem is in :
def cart_count
$redis.scard "cart#{id}"
end
any idea ?

Did you installed Redis Server:
http://redis.io/download
and Run it locallay go to where redis folder exist and write
redis-server
and define it in intalizers:
$redis = Redis.new

Related

Rails 5 - n+1 query issue inside simple_form gem

I'm trying to resolve every n+1 issue with Bullet gem in my Rails, but I can't figure out this particular problem:
_form.html.erb
<%= simple_form_for([:admin, #course, #lesson]) do |f| %>
<div class="form-inputs">
<div class="col-md-6">
<%= f.input :start_at, minute_step: 5, start_year: Date.today.year %>
</div>
<div class="col-md-6">
<%= f.input :end_at, minute_step: 5, start_year: Date.today.year %>
</div>
<div class="col-md-6">
<!--Here is the problem-->
<%= f.association :room, :label_method => lambda { |room| "#{room.title} (#{room.building.title})"}%>
<!--Here is the problem-->
</div>
<div class="col-md-6">
<%= f.association :teacher, :label_method => lambda { |teacher| "#{teacher.first_name} #{teacher.last_name}"},
collection: #course.teachers%>
</div>
</div>
<div class="col-md-12">
<div class="form-actions text-center">
<%= f.submit class: "btn btn-primary btn-lg" %>
</div>
</div>
<% end %>
Form is rendered to new.html.erb and edit.html.erb. Problem occurs on line with room association where I'm trying to get room.building.title.
Here's the screenshoot:
As you can see, I only want to display room name with its centre name, but Bullet throws an error. Problem is that I'm using that lambda function so creating a variable in a controller doesn't help (or at least I don't know how to create it properly) since problem occurs inside select box.
Here I'm including my controller:
lessons_controller.rb
module Admin
class LessonsController < Admin::AdminController
helper_method :convert_time, :convert_day
before_action :set_course
before_action :set_lesson, only: [:show, :edit, :update, :destroy]
def index
#lessons = Lesson.includes(:teacher,:course, :room => :building).where(course_id: #course).paginate(page: params[:page], per_page: 10)
# #course_lessons = #course.lessons.paginate(page: params[:page], per_page: 10)
end
def new
##room = Room.all.includes(:building)
#lesson = Lesson.new
end
def create
#lesson = Lesson.new(lesson_params)
#lesson.course = #course
if #lesson.save
flash[:success] = "Lesson was created"
redirect_to admin_course_lessons_path(#course)
else
render 'new'
end
end
def edit
end
def update
if #lesson.update(lesson_params)
flash[:success] = "Lesson was updated"
redirect_to admin_course_lessons_path(#course)
else
render 'edit'
end
end
def show
end
def destroy
#lesson.destroy
flash[:danger] = "Lesson was deleted"
redirect_to admin_course_lessons_path(#course)
end
private
def set_course
#course = Course.find(params[:course_id])
end
def set_lesson
#lesson = Lesson.find(params[:id])
end
def lesson_params
params.require(:lesson).permit(:start_at,:end_at, :room_id, :teacher_id)
end
end
end
(Actions relevant for us in this situation are new and edit)
Here are the relevant models:
room.rb
class Room < ApplicationRecord
belongs_to :building
has_many :lessons, dependent: :destroy
before_save {self.title = title.upcase_first}
before_save {self.code = code.upcase}
validates :title, presence: true,
length: { minimum: 3, maximum: 50},
uniqueness: {case_sensitive: false}
validates :code, presence: true,
length: {minimum: 2},
uniqueness: {case_sensitive: false}
validates :building_id, presence: true
end
building.rb
class Building < ApplicationRecord
has_many :rooms, dependent: :destroy
before_save {self.title = title.upcase_first}
before_save {self.code = code.upcase}
validates :title, presence: true,
length: { minimum: 3, maximum: 50},
uniqueness: true
validates :code, presence: true,
length: {minimum: 3},
uniqueness: {case_sensitive: false}
end
Sorry for this long post and my lack of knowledge. I will appreciate any feedback.
You can specify the collection option using includes in the f.association. Like this:
f.association :room, :label_method => lambda { |room| "#{room.title} (#{room.building.title})", :collection => Room.includes(:building).all }

Setting Default Value in .build method

Im trying to submit a nested form when you create a school, you can also create a admin with it. When I try to save the form with the default value of owner set to true and status set to active, it saves the form but doesnt save those values in the database
class SchoolsController < ApplicationController
before_filter :authenticate_admin!, except: [:index, :new, :create]
def show
#school = School.friendly.find(params[:id])
end
def new
#school = School.new
#admin = #school.admins.build(:owner => true, :status => "active")
end
def create
#school = School.new(school_params)
if #school.save
redirect_to new_admin_session_path
else
render 'new'
end
end
def edit
#school = School.find_by_slug(params[:id])
end
def update
#school = School.find_by_slug(params[:id])
if #school.update_attributes(school_params)
redirect_to :action => 'show', :id => #school
else
render :action => 'edit'
end
end
def team
#teams = Admin.all
end
private
def school_params
params.require(:school).permit(:school_name, :latitude, :longitude, :radius, admins_attributes: [ :first_name, :last_name, :email, :password, :password_confirmation, :image ])
end
end
class School < ActiveRecord::Base
has_many :admins
accepts_nested_attributes_for :admins
extend FriendlyId
friendly_id :school_name, use: :slugged
def should_generate_new_friendly_id?
school_name?
end
# Validation
validates :school_name, presence: true, uniqueness: true
validates :latitude, presence: true
validates :longitude, presence: true
validates :radius, presence: true, numericality: { only_integer: true }
end
%nav.navbar.navbar-default.navbar-fixed-top{role:"navigation"}
%div.container
%div.navbar-header
%button.navbar-toggle.collapsed{"data-toggle" => "collapse", "data-target" => "#navbar", "aria-expanded" => "false", "aria-controls" => "navbar"}
%span.sr-only Toggle Navigation
%span.icon-bar
%span.icon-bar
%span.icon-bar
%a.navbar-brand{"href" => "/", "id"=> "brand"} QuickAlert
%div#navbar.collapse.navbar-collapse
%ul.nav.navbar-nav.main-menu
%li.active
%a{"href" => "#"} Home
%li
%a{"href" => "#about"} About
%li
%a{"href" => "#contact"} Contact
%div.container-fluid
%div.row
%div.school-create
- if #school.errors.any?
%ul
- #school.errors.full_messages.each do |msg|
%li
= msg
%div#map-check
%h2.header School Info
= form_for #school do |f|
= f.label :school_name, "School Name"
= f.text_field :school_name, :class => 'form-control'
= f.label :latitude, "Latitude"
= f.text_field :latitude, :class => 'form-control', :id => "latitude"
= f.label :longitude, "Longitude"
= f.text_field :longitude, :class => 'form-control', :id => "longitude"
= f.label :radius, "Radius"
= f.text_field :radius, :class => 'form-control', :id => "radius"
%div.admin-fields
%h2.header Admin Info
= f.fields_for :admins do |ff|
= ff.label :first_name
= ff.text_field :first_name, :class => 'form-control'
= ff.label :last_name
= ff.text_field :last_name, :class => 'form-control'
= ff.label :email
= ff.text_field :email, :class => 'form-control'
= ff.label :password
= ff.password_field :password, :class => 'form-control'
= ff.label :password_confirmation
= ff.password_field :password_confirmation, :class => 'form-control'
= ff.file_field :image
= f.submit :class => 'submit-button btn btn-primary'

Rails and devise - assign group when user signs up

I have an app with multiple plans. For the "team" plan, the user will enter a team name and license count. When the user is created, a new team will be saved. I think I have the database part correct but I am confused with how to create the team. More specifically, my questions are: 1) How do I add the team fields to the view? Do I use form_for and nest that inside the user form? 2) How do I handle the team creation in the controller? Thanks for any help.
migration:
class CreateTeams < ActiveRecord::Migration
def change
create_table :teams do |t|
t.string :team_name
t.integer :license_count
t.timestamps
end
add_column :users, :team_id, :integer, :null => true
add_column :users, :team_admin, :boolean
end
end
controllers:
class RegistrationsController < Devise::RegistrationsController
def new
return if plan_missing
build_resource({})
self.resource.plan = params[:plan]
respond_with self.resource
end
protected
#after user has signed up
def after_inactive_sign_up_path_for(resource)
new_user_session_path
end
#after user has updated their profile, keep them on the same page
def after_update_path_for(resource)
edit_user_registration_path
end
private
def plan_missing
if params[:plan].nil?
redirect_to plans_path
true
else
false
end
end
def log
logger.debug #user.to_yaml
logger.debug params.to_yaml
end
end
models:
class User < ActiveRecord::Base
include KeyCreator
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :confirmable, :recoverable, :rememberable, :trackable, :validatable
belongs_to :teams
has_many :document_users
has_many :documents, :through => :document_users
has_many :user_billing_events, dependent: :destroy
before_create :before_create
before_destroy :before_destroy
after_destroy :after_destroy
#scopes for activeadmin
scope :new_users, -> { where("created_at >= ? and created_at <= ?", Date.today.beginning_of_day.utc, Date.today.end_of_day.utc) }
scope :admin, -> { where(:admin => true) }
validates_inclusion_of :plan, in: %w( basic pro ), message: "Plan is not valid"
attr_accessor :stripe_token, :coupon, :to_skip
def is_admin?
self.admin
end
def paid_plan
["pro", "team"].include? self.plan
end
def self.save_event(customer_id, event_type)
user = User.find_by(customer_id: customer_id)
UserBillingEvent.create!(user: user, event_type: event_type)
end
def update_card(user)
c = Stripe::Customer.retrieve(customer_id)
c.card = user.stripe_token
c.coupon = user.coupon unless user.coupon.blank?
c.save
self.customer_id = c.id
self.last_4_digits = c.cards.data.first["last4"]
self.stripe_token = nil
self.save!
true
rescue Stripe::StripeError => e
logger.error "Stripe Error: " + e.message
errors.add :base, "#{e.message}."
self.stripe_token = nil
false
end
def update_plan(user)
self.stripe_token = user.stripe_token
self.coupon = user.coupon
if self.paid_plan && !user.paid_plan
cancel_stripe
end
if !self.paid_plan && user.paid_plan
setup_stripe
end
self.plan = user.plan
self.save!
true
end
def before_create
self.api_key = create_key
self.admin = false
setup_stripe if self.paid_plan
end
def before_destroy
cancel_stripe if self.paid_plan
end
def after_destroy
self.documents.where(:document_users => {:role => "owner"}).destroy_all
self.document_users.destroy_all
end
private
def setup_stripe
return if to_skip && to_skip.include?("stripe")
logger.debug '-- setting up stripe... --'
raise "Stripe token not present. Can't create account." if !stripe_token.present?
if coupon.blank?
customer = Stripe::Customer.create(:email => self.email, :description => self.name, :card => self.stripe_token, :plan => self.plan)
else
customer = Stripe::Customer.create(:email => self.email, :description => self.name, :card => self.stripe_token, :plan => self.plan, :coupon => self.coupon)
end
self.last_4_digits = customer.cards.data.first["last4"]
self.customer_id = customer.id
self.stripe_token = nil
customer
rescue Stripe::StripeError => e
logger.error "Stripe Error: " + e.message
errors.add :base, "#{e.message}."
self.stripe_token = nil
nil #return nil
end
def cancel_stripe
return if to_skip && to_skip.include?("stripe")
logger.debug '-- cancelling stripe... --'
customer = Stripe::Customer.retrieve(customer_id)
return false if customer.nil?
subscription = customer.subscriptions.data[0]
customer.cancel_subscription if subscription.status == 'active'
self.last_4_digits = nil
self.customer_id = nil
self.stripe_token = nil
true
rescue Stripe::StripeError => e
logger.error "Stripe Error: " + e.message
errors.add :base, "#{e.message}."
self.stripe_token = nil
false
end
def trace
logger.debug '-- tracing self in user.rb'
logger.debug self.to_yaml
logger.debug '--------------------------'
end
end
class Team < ActiveRecord::Base
has_many :users
end
sign up view:
<% content_for :head do %>
<%= tag :meta, :name => "stripe-key", :content => ENV["STRIPE_PUBLIC_KEY"] %>
<%= javascript_include_tag "https://js.stripe.com/v2/" %>
<%= javascript_include_tag "stripe/application", "data-turbolinks-track" => true %>
<% end %>
<div class="container">
<h2>Sign up for <%= #user.plan.titleize %></h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name),
:html => {:role => "form", class: #user.paid_plan ? "card-form" : ""} ) do |f| %>
<%= devise_error_messages! %>
<%= f.hidden_field :plan, :value => #user.plan %>
<% if #user.plan == "team" %>
<h3 class="vpad-top5">Team Administrator - User Account</h3>
<% end %>
<div class="form-group">
<label for="name">Display Name</label>
<%= f.text_field :name, :autofocus => true, :class =>"form-control" %>
</div>
<div class="form-group">
<label for="email">Email</label>
<%= f.email_field :email, :class =>"form-control" %>
</div>
<div class="form-group">
<label for="password">Password</label>
<%= f.password_field :password, :class =>"form-control" %>
</div>
<div class="form-group">
<label for="password_confirmation">Password confirmation</label>
<%= f.password_field :password_confirmation, :class =>"form-control" %>
</div>
<% if #user.plan == "team" %>
<h3 class="vpad-top5">Team Information</h3>
<!-- I need to add fields here! -->
<% end %>
<% if #user.paid_plan %>
<h3 class="vpad-top5">Payment Information</h3>
<%= render :partial => "shared/payment_fields", :locals => {:f => f} %>
<% end %>
<%= f.submit "Sign up",:class=>'btn btn-primary' %>
<% end %>
<%= render "devise/shared/links" %>
</div>
Use Rolify gem to manage user roles.
https://github.com/RolifyCommunity/rolify
You can set a default role on user Sign Up.

Why do I get "NameError in Discussions"?

I'm currently working on a Ruby on Rails application that involves users creating discussions and commenting with microposts. It's a pretty simple concept but I'm new and have run into some trouble.
When trying to look at the discussions page (index of discussion) I get the error "NameError in Discussions#index":
undefined local variable or method `discussion' for #<#<Class:0x00000100c6e020>:0x0000010380edd8>
This is my Discussion controller:
class DiscussionsController < ApplicationController
before_filter :signed_in_user, only: [:index, :edit, :update]
def show
#user = User.find(params[:id])
#discussions = #user.discussion.paginate(page: params[:page])
#microposts = #user.micropost.paginate(page: params[:page])
end
def index
#discussions = Discussion.all
end
def create
#discussion = current_user.discussions.build(params[:discussion])
if #discussion.save
flash[:success] = "Discussion Started!"
redirect_to root_url
else
render 'static_pages/home'
end
end
def destroy
end
def edit
end
def update
end
def new
end
end
This is my Micropost form:
<% #micropost = Micropost.new %>
<% #micropost.discussion_id = discussion.id %>
<%= form_for(#micropost) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "Compose new micropost..." %>
</div>
<%= f.hidden_field :discussion_id, discussion.id%>
<%= f.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>
This is my Discussion partial:
<% content_for :script do %>
<%= javascript_include_tag 'hover_content' %>
<% end %>
<li>
<div class = "intro-bar"><span class = "intro"><%=discussion.intro %></span></div>
<div class = "content-bar">
<span class = "content"><%= discussion.content %></span>
<div class = "buttons">
<div class = "vote-neg"><%= link_to "Break Up", signup_path,class: "btn btn-large btn-breakup" %></div>
<div class = "vote-plus"><%= link_to "Stay Together", signup_path,class: "btn btn-large btn-staytogether" %></div>
</div>
</div>
</li>
<span class = "timestamp">
Posted <%= time_ago_in_words(discussion.created_at) %> ago.
</span>
<div class = "comments">
<% discussion.microposts.each do |micropost| %>
<li>
<div class = "post-comment"><%= micropost.content%></div>
</li>
<% end %>
</div>
<% if signed_in? %>
<div class = "row">
<aside class = "span4">
<section>
<%= render 'shared/micropost_form', :locals => {:discussion => discussion }%>
</section>
</aside>
</div>
<% end %>
This is my Micropost controller:
class MicropostsController < ApplicationController
before_filter :signed_in_user, only: [:create, :destroy]
def index
end
def create
#discussion = current_user.discussions.new
#micropost = current_user.microposts.build(params[:micropost])
if #micropost.save
flash[:success] = "Posted!"
redirect_to root_url
else
render 'static_pages/home'
end
end
def destroy
end
end
This is my Discussion model:
class Discussion < ActiveRecord::Base
attr_accessible :content, :intro
has_many :microposts, dependent: :destroy
belongs_to :user
validates :content, presence: true, length: { maximum: 600 }
validates :intro, presence: true
default_scope order: 'discussions.created_at DESC'
end
This is my User model:
class User < ActiveRecord::Base
attr_accessible :email, :username, :age, :sex, :points, :password, :password_confirmation
has_secure_password
has_many :microposts, dependent: :destroy
has_many :discussions, dependent: :destroy
before_save {|user| user.email = email.downcase}
before_save :create_remember_token
validates :username, presence: true, length: {maximum: 15}
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: {case_sensitive: false}
validates :age, presence: true
validates :sex, presence: true
validates :password, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
This is my Discussion index:
<% provide(:title, "Discussions") %>
<h1>Discussions</h1>
<ul class = "discussions">
<% #discussions.each do |discussion| %>
<li>
<%= render :partial =>"discussions/discussion", :locals=>{:discussion=>discussion} %>
</li>
<% end %>
</ul>
Try rewriting this line:
<%= render 'shared/micropost_form', :locals => {:discussion => discussion }%>
as:
<%= render 'shared/micropost_form', :discussion => discussion %>

Connection between three controllers rails

I have three controllers - users, stories, categories. I want when I am logged in as a administrator to create categories and then to write stories for every category. I did part of the task but in DB in table Stories category_id is empty and I cannot understand how to fix it. Here is part of my code:
stories/new.html.erb:
<%= form_for(#story) do |f| %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :category %><br />
<%= f.collection_select :category_id, #categories, :id, :title %>
</div>
<div class="field">
<%= f.label :content %><br />
<%= f.text_area :content %>
</div>
<div class="actions">
<%= f.submit "Add" %>
</div>
<% end %>
stories_controller.rb:
class StoriesController < ApplicationController
before_filter :admin_user
def new
#story = Story.new
#categories = Category.all
#title = "Add news"
end
def create
#categories = Category.all
#story = current_user.stories.build(params[:story])
if #story.save
flash[:success] = "Successfullly added news"
redirect_to #story
else
#title = "Add news"
render 'new'
end
end
private
def admin_user
redirect_to(root_path) unless current_user.admin?
end
end
story.rb:
class Story < ActiveRecord::Base
attr_accessible :title, :content
belongs_to :user
belongs_to :category
validates :title, :presence => true
validates :content, :presence => true
validates :user_id, :presence => true
default_scope :order => 'stories.created_at DESC'
end
category.rb:
class Category < ActiveRecord::Base
attr_accessible :title
has_many :stories
validates :title, :presence => true,
:length => { :within => 6..40 }
end
user.rb:
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :name, :email, :password, :password_confirmation
has_many :stories
validates :name, :presence => true,
:length => { :maximum => 50 }
validates :email, :presence => true
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => true
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
before_save :encrypt_password
def has_password?(submitted_password)
encrypted_password == encrypt(submitted_password)
end
def self.authenticate(email, submitted_password)
user = find_by_email(email)
return nil if user.nil?
return user if user.has_password?(submitted_password)
end
def self.authenticate_with_salt(id, cookie_salt)
user = find_by_id(id)
(user && user.salt == cookie_salt) ? user : nil
end
private
def encrypt_password
self.salt = make_salt unless has_password?(password)
self.encrypted_password = encrypt(password)
end
def encrypt(string)
secure_hash("#{salt}--#{string}")
end
def make_salt
secure_hash("#{Time.now.utc}--#{password}")
end
def secure_hash(string)
Digest::SHA2.hexdigest(string)
end
end
You need add attr_accessible :category_id to your story model
Its preventing mass assignment in your controllers create method. Alternatively you could pull out the category_id from your params hash and assign it on a separate line.

Resources