Rails Association Undefined method error - ruby-on-rails

I would like to add "category" function.
I associated article.rb and category.rb.
However, undefined method `categories' for nil:NilClass was present.
I have no idea.If you know any solution, please tell me.
Index.html.erb
<% unless #article.categories.blank? %>
<% #articles.categories.each do |category|%>
<%= link_to category.name,article_path(category_id:category.id)%>
<%end%>
<%end%>
article.rb
class Article < ApplicationRecord
scope :from_category, -> (category_id) { where(id: article_ids = ArticleCategory.where(category_id: category_id).select(:article_id))}
validates :title, presence: true
validates :content, presence: true
mount_uploader :image,ImageUploader
has_many :categories, through: :article_categories
has_many :article_categories, dependent: :destroy
def save_categories(tags)
current_tags = self.categoires.pluck(:name) unless self.categories.nil?
old_tags = current_tags - tags
new_tags = tags - current_tags
old_tags.each do |old_name|
self.categories.delete Category.find_by(name:old_name)
end
new_tags.each do |new_name|
article_category = Category.find_or_create_by(name:new_name)
self.categories << article_category
end
end
end
category.rb
class Category < ApplicationRecord
validates :name,presense: true,length:{maximum:50}
has_many :articles,through: :article_categories
has_many :article_categories,dependent: :destroy
end
article_category.rb
class ArticleCategory < ApplicationRecord
belongs_to :article
belongs_to :category
validates :article_id,presense:true
validates :category_id,presense:true
end
articles_controller.rb
class ArticlesController < ApplicationController
before_action :set_post, only: [:show,:edit,:update]
before_action :authenticate_user!, :except => [:index,:show]
before_action :set_article_tags_to_gon, only: [:edit]
def index
if params[:category_id]
#selected_category = Category.find(params[:category_id])
#articles= Article.from_category(params[:category_id]).page(params[:page])
else
#articles= Article.all.page(params[:page])
end
#articles = Article.page params[:page]
end
def show
end
def new
#article = Article.new
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to articles_path
else
render 'articles/new'
end
end
def edit
#category_list = #article.categories.pluck(:name).join(",")
end
def update
if #article.update(article_params)
redirect_to articles_path
else
redirect_to 'edit'
end
end
private
def article_params
params[:article].permit(:title,:content,:image,:tag_list,:category)
end
def set_post
#article = Article.find(params[:id])
end
error message

You're calling categories on a nil object, in this case #article. Did you mean to call it on #articles?
If not, you will need to define #article in the index action of your controller.

Related

Why am i getting two different urls for the same "story" in my rails app?

I recently created a profile page for the users of the app am developing but along the way i noticed that the URL for the story originally is a little different from the same story on the users page. e.g normal url is "http://localhost:3000/genres/action/stories/37" while it is "http://localhost:3000/genres/absurdist/stories/37", meanwhile the story originally belongs to "action genre" and not "absurdist". Meanwhile, the two urls directs to the normal story page.
genre.rb
class Genre < ApplicationRecord
belongs_to :user
has_many :stories, dependent: :destroy
is_impressionable
extend FriendlyId
friendly_id :name, use: :slugged
def should_generate_new_friendly_id?
name_changed?
end
end
story.rb
class Story < ApplicationRecord
belongs_to :genre
belongs_to :user
has_many :episodes, dependent: :destroy
is_impressionable
extend FriendlyId
friendly_id :title, use: :slugged
def should_generate_new_friendly_id?
title_changed?
end
has_attached_file :image, size: { less_than: 1.megabyte }, styles: { medium: "300x300#", wide: "200x400#" }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
scope :of_followed_users, -> (following_users) { where user_id: following_users }
end
profiles_controller
class ProfilesController < ApplicationController
before_action :find_user
before_action :find_genre
before_action :owned_profile, only: [:edit, :update]
before_action :authenticate_user!
def show
#stories = User.find_by(user_name: params[:user_name]).stories.order('created_at DESC')
impressionist(#user)
end
def edit
end
def update
if #user.update(profile_params)
flash[:success] = 'Your profile has been updated.'
redirect_to profile_path(#user.user_name)
else
#user.errors.full_messages
flash[:error] = #user.errors.full_messages
render :edit
end
end
private
def profile_params
params.require(:user).permit(:avatar, :bio)
end
def find_user
#user = User.find_by(user_name: params[:user_name])
end
def find_genre
#genre = Genre.friendly.find_by(params[:slug])
end
def owned_profile
#user = User.find_by(user_name: params[:user_name])
unless current_user == #user
flash[:alert] = "That profile does not belong to you"
redirect_to root_path
end
end
end
profiles show
<div class="container my-5">
<div class="card-columns clearfix">
<%= render #user.stories %>
</div>
</div>

DB rolls back on create action

I'm trying to create a form with a series of checks to prevent duplicates during the simultaneous creation of three model records: one for the parent (assuming it doesn't exist), one for its child (assuming it doesn't exist), and one for a join table between the child and the User (to allow the User to have their own copy of the Song object).
In the current state of the code, The checks seemingly pass, but
the server logs show ROLLBACK, and nothing gets saved
to the database EXCEPT the parent object (artist).
When I try to use the ids of the object, I get the error undefined method id for nil:NilClass, or "couldn't find object without an ID".
The following code is in my controller:
class SongsController < ApplicationController
before_action :authenticate_user!
def create
#artist = Artist.find_by(name: params[:artist][:name].strip.titleize) #look for the artist
#song = Song.find_by(title: params[:artist][:songs_attributes]["0"][:title].strip.titleize)
if #artist.present? && #song.present?
#user_song = current_user.user_songs.find(#song_id)
if #user_song.present?
render html: "THIS SONG IS ALREADY IN YOUR PLAYLIST"
render action: :new
else
#user_song = UserSong.create(user_id: current_user.id, song_id: #song.id)
redirect_to root_path
end
elsif #artist.present? && !#song.present?
#song = #artist.songs.build(title: params[:artist][:songs_attributes]["0"][:title].strip.titleize, lyrics: params[:artist][:songs_attributes]["0"][:lyrics].strip)
#user_song = UserSong.create(user_id: current_user.id, song_id: #song.id)
redirect_to root_path
elsif !#artist.present?
#artist = Artist.create(name: params[:artist][:name].strip.titleize)
#song = #artist.songs.build(title: params[:artist][:songs_attributes]["0"][:title].strip.titleize, lyrics: params[:artist][:songs_attributes]["0"][:lyrics].strip)
#user_song = UserSong.create(user_id: current_user.id, song_id: #song.id)
redirect_to root_path
else
render html: "SOMETHING WENT WRONG. CONTACT ME TO LET ME KNOW IF YOU SEE THIS MESSAGE"
end
end
def index
#songs = Song.all
end
def new
#artist = Artist.new
#artist.songs.build
#user_song = UserSong.new(user_id: current_user.id, song_id: #song_id)
end
def show
#song_id = params["song_id"]
#song = Song.find(params[:id])
end
def destroy
UserSong.where(:song_id => params[:id]).first.destroy
flash[:success] = "The song has been from your playlist"
redirect_to root_path
end
def edit
#song = Song.find(params[:id])
#artist = Artist.find(#song.artist_id)
end
def update
end
private
def set_artist
#artist = Artist.find(params[:id])
end
def artist_params
params.require(:artist).permit(:name, songs_attributes: [:id, :title, :lyrics])
end
def set_song
#song = Song.find(params["song_id"])
end
end
The models:
class Artist < ApplicationRecord
has_many :songs
accepts_nested_attributes_for :songs, reject_if: proc { |attributes| attributes['lyrics'].blank? }
end
class Song < ApplicationRecord
belongs_to :artist
has_many :user_songs
has_many :users, :through => :user_songs
end
class UserSong < ApplicationRecord
belongs_to :song
belongs_to :user
end
Sorry if I haven't abstracted enough. Not really sure how, given that there's no error message, just a rollback (without any validations present in any of the controllers).
Thanks to #coreyward and his pointing out of the fat-model skinny-controller lemma (never knew that was a thing), I was able to cut the code down and arrive at a solution immediately. In my models, I used validates_uniqueness_of and scope in order to prevent duplication of records. In my controller, I used find_or_create_by to seal the deal.
To whom it may concern, the final code is as follows:
class SongsController < ApplicationController
before_action :authenticate_user!
def create
#artist = Artist.find_or_create_by(name: params[:artist][:name].strip.titleize)
#song = #artist.songs.find_or_create_by(title: params[:artist][:songs_attributes]["0"][:title].strip.titleize) do |song|
song.lyrics = params[:artist][:songs_attributes]["0"][:lyrics].strip
end
#user_song = current_user.user_songs.find_or_create_by(song_id: #song.id) do |user_id|
user_id.user_id = current_user.id
end
redirect_to root_path
end
class Song < ApplicationRecord
validates_uniqueness_of :title, scope: :artist_id
belongs_to :artist
has_many :user_songs
has_many :users, :through => :user_songs
end
class Artist < ApplicationRecord
validates_uniqueness_of :name
has_many :songs
accepts_nested_attributes_for :songs, reject_if: proc { |attributes| attributes['lyrics'].blank? }
end
class UserSong < ApplicationRecord
validates_uniqueness_of :song_id, scope: :user_id
belongs_to :song
belongs_to :user
end

undefined method `total_pages' for #<Recipe::ActiveRecord_Relation:0x007fb4045fec58>

I would like to know if someone sees the problem
I am using the gem will_paginate
My Recipe model:
class Recipe < ActiveRecord::Base
belongs_to :user
has_many :ingredients, dependent: :destroy
has_many :reviews, dependent: :destroy
self.per_page = 10
end
My RecipesController:
class RecipesController < ApplicationController
skip_before_action :authenticate_user!
def index
if params[:search]
#recipes = Recipe.search(params[:search]).page(params[:page]).order("created_at DESC")
else
#recipes = Recipe.all.page(params[:page]).order('created_at DESC')
end
end
def show
#review = Review.new
#recipe = Recipe.find(params[:id])
#user = User.find(#recipe.user_id)
#full_name = #recipe.user.first_name + " " + #recipe.user.last_name
end
end
app/views/recipes/index.html.erb:
<%= will_paginate #recipes %>
For the people who might care or have the same problem. I found the solution:
I changed self.per_page = 10 to WillPaginate.per_page = 10 inside the Recipe model.

undefined method `team_id' - Ruby on Rails

The error is undefined method 'team_id' for Player:0x007fb5f41f3838.
I am trying to edit players and I am not able to do that because of an undefined method.
My guess is it has something to do with my relations. I am learning relations between models so they may not be correct.
This is my Player Model
class Player < ActiveRecord::Base
validates_length_of :description, :maximum=>4000
has_many :descriptions, through: :fouls
has_many :fouls, as: :foul_by_id
has_many :fouls, as: :foul_on_id
belongs_to :team
end
This is my Player Controller
class PlayersController < ApplicationController
before_action :authenticate_user!
before_action :most_recent_fouls
def index
#players = Player.all
end
def show
#player = Player.find(params[:id])
end
def new
#player = Player.new
end
def create
#player = Player.new(players_params)
if #player.save
redirect_to(:action => "index")
else
render("new")
end
end
def edit
#player = Player.find(params[:id])
end
def update
#player = Player.find(params[:id])
if #player.update_attributes(players_params)
redirect_to(:action => "show", :id => #player.id)
else
render("index")
end
end
def destroy
player = Player.find(params[:id]).destroy
redirect_to(:action => "index")
end
private
def players_params
params.require(:player).permit(:name, :number, :position, :bios, :descriptions, :team_id)
end
end
Because of my gut saying that it has to do with relations, here is my Team Model
class Team < ActiveRecord::Base
has_many :players
validates :name, presence: true
end
My migration table for Player
class CreatePlayers < ActiveRecord::Migration
def change
create_table :players do |p|
p.string :name
p.string :number
p.string :position
p.string :bio
p.string :description
p.integer :team_id
p.timestamps
end
end
end
Any help is appreciated. Please explain your answer. Tell me if you need any more code to be displayed.

Having trouble counting page views using "impressionist" gem (Ruby on Rails)

Update #2
I've got it working but how can I make it count each refresh? Even if I refresh on a user's profile (/users/3 for example), I want it to count.
Widget.rb
class Widget < ActiveRecord::Base
is_impressionable
def impressionist_count
impressions.size
end
end
Widgets controller
WidgetsController < ApplicationController
def show
#widget = Widget.find(params[:id])
impressionist(#widget,message:"wtf is a widget?") #message is optional
end
end
Added Is_Impressionable to the user model
and here's the code I'm using for show.html.erb view
<%= #user.impressionist_count(:filter=>:all) %>
Update #1
When I make the change noted below in Said's answer and try it in the "Widgets" controller and "Widget" module, I get this error now:
NoMethodError in Users#show
undefined method `impressionist_count' for nil:NilClass
Here's the user.rb
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_secure_password
has_many :microposts, dependent: :destroy
has_many :impressions, :as=>:impressionable
has_many :relationships, foreign_key: "follower_id", dependent: :destroy
has_many :followed_users, through: :relationships, source: :followed
has_many :reverse_relationships, foreign_key: "followed_id",
class_name: "Relationship",
dependent: :destroy
has_many :followers, through: :reverse_relationships, source: :follower
before_save { |user| user.email = user.email.downcase }
before_save :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_sensitive: false }
validates :password, length: { minimum: 6 }
validates :password_confirmation, presence: true
def following?(other_user)
relationships.find_by_followed_id(other_user.id)
end
def follow!(other_user)
relationships.create!(followed_id: other_user.id)
end
def unfollow!(other_user)
relationships.find_by_followed_id(other_user.id).destroy
end
def feed
Micropost.from_users_followed_by(self)
end
def impressionist_count
impressions.size
end
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
and here's the Users controller
class UsersController < ApplicationController
before_filter :signed_in_user,
only: [:index, :edit, :update, :destroy, :following, :followers]
before_filter :correct_user, only: [:edit, :update]
before_filter :admin_user, only: :destroy
def index
#users = User.paginate(page: params[:page]).all
end
def show
#user = User.find(params[:id])
#microposts = #user.microposts.paginate(page: params[:page])
end
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
sign_in #user
flash[:success] = "Demoapp!"
redirect_to root_url
else
render 'new'
end
end
def edit
end
def update
if #user.update_attributes(params[:user])
sign_in #user
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User destroyed"
redirect_to users_path
end
def following
#title = "Follow"
#user = User.find(params[:id])
#users = #user.followed_users.paginate(page: params[:page])
render 'show_follow'
end
def followers
#title = "Following"
#user = User.find(params[:id])
#users = #user.followers.paginate(page: params[:page])
render 'show_follow'
end
private
def correct_user
#user = User.find(params[:id])
redirect_to root_path unless current_user?(#user)
end
def admin_user
redirect_to root_path unless current_user.admin?
end
end
Original Post
What did I do wrong below?
I added the gem and ran the db migration.
Then I created a new "Widgets" controller file in app\controllers
WidgetsController < ApplicationController
def show
#widget = Widget.find
impressionist(#widget)
end
end
Then I created a new "Widget" model in app/models
class Widget < ActiveRecord::Base
is_impressionable
end
Then I added
<%= #widget.impressionist_count %>
in the show.html.erb view
What I am trying to count is the # of user's profile views. Throughout the website, you can click on a username and it will go into their profile. I just want to show the counter of how many times were clicked into their profile.
Thanks
Seems the problem is in show action,
instead:
#widget = Widget.find
try this
#widget = Widget.find(params[:id])
UPDATE: 1
you should add is_impressionable to your user model

Resources