undefined method `following' for nil:NilClass - ruby

I am working on a project similar to a twitter clone. However, I am running into an error that is the following: undefined method `following' for nil:NilClass in my controller. So, to start, here is my controller:
class EpicenterController < ApplicationController
def feed
#Here we initialize the array that will hold tweets from the current_user's
following list.
#following_tweets = []
Tweet.all.each do |tweet|
if current_user.following.include?(tweet.user_id)
#following_tweets.push(tweet)
end
end
end
def show_user
#user = User.find(params[:id])
end
def now_following
#user = User.find(params[:follow_id])
#Adding the user.id of the user you want to follow to your 'follow' array
attribute
current_user.following.push(params[:follow_id].to_i)
current_user.save
end
def unfollow
end
end
Here is my model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
serialize :following, Array
has_many :tweets
validates :username, presence: true, uniqueness: true
end
My Schema:
ActiveRecord::Schema.define(version: 20160811164903) do
create_table "tweets", force: :cascade do |t|
t.string "message"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name"
t.string "username"
t.text "bio"
t.string "location"
t.text "following"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name:
"index_users_on_reset_password_token", unique: true
end
Finally my application controller:
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
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :username,
:bio,
:location, :following])
devise_parameter_sanitizer.permit(:account_update, keys: [:name,
:username, :bio, :location, :following])
end
end
Thank you for any help that may be provided. Please let me know if you need to see something else and I will add it.
Stack Trace:
NoMethodError (undefined method `following' for nil:NilClass):
app/controllers/epicenter_controller.rb:8:in `block in feed'
app/controllers/epicenter_controller.rb:7:in `feed'
Rendered /Users/mikecuddy/.rvm/rubies/ruby-
2.2.1/lib/ruby/gems/2.2.0/gems/actionpack-
4.2.6/lib/action_dispatch/middleware/templates/rescues/_source.erb (3.9ms)
Rendered /Users/mikecuddy/.rvm/rubies/ruby-
2.2.1/lib/ruby/gems/2.2.0/gems/actionpack-
4.2.6/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
(2.7ms)
Rendered /Users/mikecuddy/.rvm/rubies/ruby-
2.2.1/lib/ruby/gems/2.2.0/gems/actionpack-
4.2.6/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (0.9ms)
Rendered /Users/mikecuddy/.rvm/rubies/ruby-
2.2.1/lib/ruby/gems/2.2.0/gems/actionpack-
4.2.6/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb
within rescues/layout (63.4ms)
Rendered /Users/mikecuddy/.rvm/rubies/ruby-
2.2.1/lib/ruby/gems/2.2.0/gems/web-console-
2.3.0/lib/web_console/templates/_markup.html.erb (0.4ms)
Rendered /Users/mikecuddy/.rvm/rubies/ruby-
2.2.1/lib/ruby/gems/2.2.0/gems/web-console-
2.3.0/lib/web_console/templates/_inner_console_markup.html.erb within
layouts/inlined_string (0.3ms)
Rendered /Users/mikecuddy/.rvm/rubies/ruby-
2.2.1/lib/ruby/gems/2.2.0/gems/web-console-
2.3.0/lib/web_console/templates/_prompt_box_markup.html.erb within
layouts/inlined_string (0.3ms)
Rendered /Users/mikecuddy/.rvm/rubies/ruby-
2.2.1/lib/ruby/gems/2.2.0/gems/web-console-
2.3.0/lib/web_console/templates/style.css.erb within layouts/inlined_string
(0.5ms)
Rendered /Users/mikecuddy/.rvm/rubies/ruby-
2.2.1/lib/ruby/gems/2.2.0/gems/web-console-
2.3.0/lib/web_console/templates/console.js.erb within layouts/javascript
(62.0ms)
Rendered /Users/mikecuddy/.rvm/rubies/ruby-
2.2.1/lib/ruby/gems/2.2.0/gems/web-console-
2.3.0/lib/web_console/templates/main.js.erb within layouts/javascript
(0.3ms)
Rendered /Users/mikecuddy/.rvm/rubies/ruby-
2.2.1/lib/ruby/gems/2.2.0/gems/web-console-
2.3.0/lib/web_console/templates/error_page.js.erb within layouts/javascript
(0.6ms)
Rendered /Users/mikecuddy/.rvm/rubies/ruby-
2.2.1/lib/ruby/gems/2.2.0/gems/web-console-
2.3.0/lib/web_console/templates/index.html.erb (139.5ms)

current_user is nil for not logged in users, so you'll need to handle it:
if user_signed_in?
current_user.following # ...
else
store_location_for :user, request.path
redirect_to new_user_session_path, alert: 'You need to be logged in to do that.'
end
or
class EpicenterController < ApplicationController
before_action :authenticate_user! #, only: [:feed, :now_following] (optional)
# ...
end
if your controller is mostly intended for signed in users (which seems like it).

Related

Sinatra and Ruby error: ActiveRecord::RecordNotUnique at /shoes/1

Good morning, I'm using Sinatra and Ruby to create a running app that logs your runs. I keep getting this error anytime I try to save a run:
ActiveRecord::RecordNotUnique at /shoes/1
Here is my controller for this route:
post '/shoes/:id' do
#shoe = Shoe.find(params[:id])
if logged_in?
#runs = #shoe.runs.build(params)
#newest_run = (#shoe.current_mileage.to_i + #runs.latest_run.to_i)
#shoe.current_mileage = #newest_run
#runs.save
flash[:message] = "A new run has been added!"
redirect to("/shoes/#{#shoe.id}")
else
redirect to("/login")
end
end
I've been trying to debug this all morning and can't find the reason as to why the run can't happen. I have 3 models as well: A user has_many shoes; a shoe belongs_to a user and has_many runs; a run belongs_to a shoe. Could there be an issue with the associations I have set up?
Edited: Here is my schema:
ActiveRecord::Schema.define(version: 20200708142633) do
create_table "runs", force: :cascade do |t|
t.integer "latest_run"
t.date "date"
t.string "location"
t.integer "shoe_id"
end
create_table "shoes", force: :cascade do |t|
t.string "name"
t.date "date"
t.integer "new_mileage"
t.integer "current_mileage"
t.integer "latest_run"
t.decimal "price", precision: 10, scale: 3
t.integer "user_id"
end
create_table "users", force: :cascade do |t|
t.string "username"
t.string "email"
t.string "password_digest"
end
end
Edited #2:
Here are my params:
{"latest_run"=>"150", "location"=>"Kansas", "date"=>"2020-07-07", "id"=>"1"}
Here is are my Shoe and Run models:
class Shoe < ActiveRecord::Base
belongs_to :user
has_many :runs
validates :name, :date, :new_mileage, :current_mileage, :price, presence: true
end
class Run < ActiveRecord::Base
belongs_to :shoe
validates_presence_of :latest_run, :date, :location, :shoe_id
end
Thanks everyone!

before_action and nested attributes for models

The question is really simple.
Please, take a look at my schema:
ActiveRecord::Schema.define(version: 20170812094528) do
create_table "items", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "parent_id"
end
create_table "parents", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "item_id"
end
end
This is how models looks like:
class Parent < ApplicationRecord
has_one :item
accepts_nested_attributes_for :item
before_create :set_something
def set_something
self.item.build
end
end
and
class Item < ApplicationRecord
belongs_to :parent
end
The question: When creating a Parent, why does it raise the following error?
undefined method `build' for nil:NilClass
How should I set this up so that I can add and item record at the same time as creating a parent?
Try using
def set_something
build_item
end
The model Parent has_one :item. In Rails, the has_one association adds a helper method build_association(attributes = {}) to the owner class, and not association.build(attributes = {}). This is the reason that you are getting the error undefined method 'build' for nil:NilClass.
Please see the has_one documentation for more details on has_one association.

Rails Paperclip - Duplicating the attachment file name in another field

I've got the following table:
create_table "documents", force: true do |t|
t.string "title"
t.integer "subject_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "attachment_file_name"
t.string "attachment_content_type"
t.integer "attachment_file_size"
t.datetime "attachment_updated_at"
end
Whenever I upload a file (using Paperclip), I want to duplicate the param of 'attachment_file_name' to 'title'.
This app is an API, but I'm using a debugs_controller to test it.
DebugsController
class DebugsController < ApplicationController
def index
#document = Document.new
#documents = Document.all
#subject = Subject.new
end
end
debugs/index.html.erb
<form action="http://0.0.0.0:3000/documents" method="POST" enctype="multipart/form-data">
<input name="document[title]" type="text" placeholder="doc naam">
<input name='document[attachment]' type="file">
<input name="document[subject_id]" type="text" placeholder="Subject id">
<input type="submit">
</form>
DocumentsController
class DocumentsController < ApplicationController
before_action :set_document, only: [:show, :update, :destroy]
skip_before_action :verify_authenticity_token
respond_to :json
def index
#documents = Document.all
end
def new
#document = Document.new
#documents = Document.all
end
def show
end
def create
#document = Document.new(document_params)
#document.title = params[:attachment].original_filename
if #document.save
respond_with(#document, status: :created)
else
respond_with(#document, status: 403)
end
end
def update
if #document.update(document_params)
respond_with(#document)
else
respond_with(#document.errors, status: :unprocessable_entity)
end
end
def destroy
#document.destroy
respond_with(#document, status: :destroyed)
end
private
def set_document
#document = Document.find(params[:id])
end
def document_params
params.require(:document).permit(:title, :attachment, :subject_id)
end
end
Document.rb
class Document < ActiveRecord::Base
belongs_to :subject
has_many :notes
has_attached_file :attachment, url: '/system/:attachment/:id_partition/:basename.:extension'
validates_attachment :attachment, presence: {
message: 'You have to upload a file!' }, content_type: {
content_type: %w( application/pdf ), message: 'PDF files only.' }, size: {
in: 0..10.megabytes, message: 'The maximum file-size is 10MB.' }
validates :subject_id, presence: { message: 'Assign your document to a case!' }
end
This outputs 'undefined method `original_filename' for nil:NilClass' for me.
Params:
{"document"=>{"title"=>"",
"attachment"=>#<ActionDispatch::Http::UploadedFile:0x007fbcea87c518 #tempfile=#<Tempfile:/var/folders/sy/9v_t59x974qg_m2nvmcyvkjr0000gn/T/RackMultipart20141202-14285-z5aj46>,
#original_filename="Teamsweet.pdf",
#content_type="application/pdf",
#headers="Content-Disposition: form-data; name=\"document[attachment]\"; filename=\"Teamsweet.pdf\"\r\nContent-Type: application/pdf\r\n">,
"subject_id"=>"1"},
"format"=>:json}
Does anyone know how I can duplicate the contents of the 'attachment_file_name' to the 'title' field of Documents? Also; is it possible to remove the extention of the uploaded file in the process of duplicating the file name?
You can do that in the model instead of in the controller.
class Document < ActiveRecord::Base
before_save :set_title
def set_title
self.title = self.attachment_file_name
end
...
end

How can I combine two Rails 4 where queries that query either side of a boolean condition?

Question:
Is there a way to combine the following two queries (including the assignments) into one query? I'm not sure how much time I'd really save. In other words, I'm not sure if it is worth it, but I'd like to be as efficient as possible.
#contacts = #something.user.contacts.where.not(other_user_id: 0)
#user_contacts = #something.user.contacts.where(other_user_id: 0)
More context:
Here is my contacts table from schema.rb:
create_table "contacts", force: true do |t|
t.string "name"
t.string "email"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "profile_picture"
t.string "phone_number"
t.integer "other_user_id"
end
And here is the important stuff from the users table:
create_table "users", force: true do |t|
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
...
t.string "first_name"
t.string "second_name"
end
And here is the pertinent information of the models:
class Contact < ActiveRecord::Base
belongs_to :user
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
validates :name, presence: true
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }
validates :user_id, presence: true
def get_email_from_name
self.email
end
end
[...]
class User < ActiveRecord::Base
has_many :contacts
has_many :relationships,
foreign_key: 'follower_id',
dependent: :destroy
has_many :reverse_relationships,
foreign_key: 'followed_id',
class_name: 'Relationship',
dependent: :destroy
has_many :commitments,
class_name: 'Commitment',
dependent: :destroy
has_many :followers,
through: :reverse_relationships
has_many :followed_users,
through: :relationships,
source: :followed
[...]
before_save { email.downcase! || email }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
validates :email,
presence: true,
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
[...]
def follow!(other_user)
relationships.create!(followed_id: other_user.id)
if create_contact?(self, id, other_user.id)
create_contact(other_user.name,
other_user.email,
self.id,
other_user.id,
other_user.gravatar_url)
elsif create_contact?(other_user, other_user.id, id)
create_contact(name, email, other_user.id, id, gravatar_url)
end
end
def create_contact?(user, followed_id, follower_id)
user.admin? && ! Relationship.where(followed_id: followed_id, follower_id: follower_id).empty?
end
def create_contact(name, email, user_id, other_user_id, profile_picture)
Contact.create!(name: name,
email: email,
user_id: user_id,
other_user_id: other_user_id,
profile_picture: profile_picture)
end
def unfollow!(other_user)
relationships.find_by(followed_id: other_user.id).destroy
Contact.destroy_all(user_id: self.id, other_user_id: other_user.id)
end
[...]
end
The other contacts that may not have an account with the website (yet), and I'd like to distinguish that in the view. So I keep track of which contacts I import through Google contacts using the omniauth gem. For the other contacts, I gather the other users that are friends with current_user.
Goal:
I'd like to save these two record collections to use in the view, but I'd like to avoid looking through all the user's contacts twice, checking the same column in each pass-through.
Any ideas? I'm sure there are lots of ways this can be done, and I'd like to learn as much as I can from this! Thanks in advance!
You can use Array#partition to split up the array in memory, after the query was performed.
#user_contacts, #contacts = #something.user.contacts.partition{|u| other.id == 0 }
However checking for this magic 0 id is smelly. You should try to get rid of such special cases whenever possible.
It is not the best solution, but if you think partition hard to understand, it can be an optional.
#user_contacts, #users = [], []
#something.user.contacts.each do |record|
if record.other_user_id == 0
#user_contacts << record
else
#users << record
end
end

Rails ActiveRecord Ignoring Params and Saving Nil Data

This is stumping me; For some reason the db is saving the record with nil fields instead of my params. Can anyone help me understand why ActiveRecord isn't using my params?
db migration:
class CreateRoutes < ActiveRecord::Migration
def change
create_table :routes do |t|
t.integer :user_id
t.string :start_address
t.string :end_address
t.text :waypoints
t.text :schedule
t.integer :duration
t.timestamps
end
add_index :routes, :user_id
end
end
route.rb:
class Route < ActiveRecord::Base
attr_accessor :start_address, :end_address, :waypoints, :schedule, :duration
belongs_to :user
#serialize :waypoints, :schedule
validates :user_id, presence: true
validates :start_address, presence: true
validates :end_address, presence: true
validates :schedule, presence: true
validates :duration, presence: true, numericality: { only_integer: true, greater_than: 0 }
end
routes_controller.rb:
class RoutesController < ApplicationController
.
.
.
def create
logger.debug "\n\n*** #{params[:route]} ***"
#route = current_user.routes.build(params[:route])
logger.debug "*** The route is #{#route.inspect} ***\n\n"
if #route.save
flash[:success] = "Route saved!"
redirect_to user_path(current_user)
else
render 'new'
end
end
.
.
.
end
logger output:
*** {"start_address"=>"123 Sample St.", "end_address"=>"321 Elpmas St.", "waypoints"=>"None", "schedule"=>"Mondays", "duration"=>"15"} ***
*** The route is #<Route id: nil, user_id: 1, start_address: nil, end_address: nil, waypoints: nil, schedule: nil, duration: nil, created_at: nil, updated_at: nil> ***
The attr_accessors will overwrite the accessors generated by ActiveRecord, causing them to not be persisted in the DB--they'll be like plain old Ruby properties/members instead of the meta-programmed magic of ActiveRecord.
DB properties (persistent properties) can have things like attr_accessible, though.

Resources