So, this is pretty simple (I think) but I still have a hard time wrapping my head around this. I have an app, where as a User that is signed in can create Topics and Bookmarks which are nested in the topics. A User can also Like a bookmark another user created.
On my users/show.html.erb I'm trying to make a list of all the bookmarks and likes a user has created. Both have user_id's which I would assume that's how I could call them, I'm just retarded and need some help.
What would I put in my user_controller and my user/show.html.erb files?
Thanks for the help!
Here is my User.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
has_many :topics
has_many :bookmarks, dependent: :destroy
has_many :likes, dependent: :destroy
#liked method takes a bookmark object and returns a like object if one exists
def liked(bookmark)
likes.where(bookmark_id: bookmark.id).first
end
end
Like.rb
class Like < ActiveRecord::Base
#considered a simple join table, that represents a relation between two objects (user/bookmark)
belongs_to :user
belongs_to :bookmark
end
Bookmark.rb
class Bookmark < ActiveRecord::Base
belongs_to :topic
belongs_to :user
has_many :likes, dependent: :destroy
end
In your user_controller:
def show
#user = User.find(user_params[:id])
end
def user_params
params.require(:user).permit(:id)
end
In your show.html.erb:
<% #user.bookmarks.each do |bookmark| %>
<%= bookmark.name %> #guessing here as I don't know your DB schema
<% end %>
<% #user.likes.each do |like| %>
<%= like.name %> #still guessing
<% end %>
You said Bookmarks are nested in Topics, but you don't show that in your code. Instead of User model having:
has_many :bookmarks, dependent: :destroy
it should be
has_many :bookmarks, through: :topics, dependent: :destroy
You can still access bookmarks the same way:
#user.bookmarks
Related
I am pulling game data from an API (https://github.com/games-directory/api-giantbomb) where users can search through games and add it to their library. However I can't get the Create method working that is supposed to create an instance of the game called from the API and post it to the user's library page.
I have my associations set up across four models: Game, User, Library, and Library_Game:
Game.rb
class Game < ApplicationRecord
has_many :library_games
has_many :libraries, through: :library_games
has_many :users, through: :libraries
serialize :data
def fetch_data
game = GiantBomb::Game.detail(id)
self.data = Hash[game.instance_variables.map { |var| [var.to_s[1..-1], game.instance_variable_get(var)] } ]
end
def to_giant_bomb_game
GiantBomb::Game.new(data)
end
end
User.rb
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :libraries
has_many :games, through: :libraries
def has_game?(game)
games.where(id: game.id).exist?
end
end
Library.rb
class Library < ApplicationRecord
belongs_to :user
has_many :library_games
has_many :games, through: :library_games
end
Library_Game.rb
class LibraryGame < ApplicationRecord
belongs_to :library
belongs_to :game
has_one :user, through: :library
end
I am routing the create method through the Games Controller. Here is my create method along with the strong params.
def create
#library_game = Game.new(game_params)
#library_game.fetch_data
#library_game.save
redirect_to library_path
end
private
def game_params
params.require(:game).permit(:data)
end
end
I get an error on my fetch_data method saying "undefined method `each' for nil:NilClass". However if I take out the #library_games.fetch_data part of my create method, it redirects to my library but there is no instance of the game.
My link_to in my view that is supposed to attach the game to a user's library:
<%= link_to 'Add to library', create_path(current_user, game: game), method: :post %>
And the library controller's index that is supposed to display the games.
class LibraryController < ApplicationController
def index
#library_games = User.find(params[:id]).games
end
end
The view for the library index:
<% if #library_games.exists? %>
<% #library_games.map(&:to_giant_bomb_game).each do |game| %>
#etc.
What should I be doing in my create method to create a new instance of the API data that can save to a user's library?
I have nested relationships and built them according to the Rails Guide.
A User has many Collections that have many Sections each containing many Links. When creating a new Link though, the user_id is not being assigned but is always nil. The section_id and collection_id are being set correctly.
Controller
class Api::V1::LinksController < Api::V1::BaseController
acts_as_token_authentication_handler_for User, only: [:create]
def create
#link = Link.new(link_params)
#link.user_id = current_user
authorize #link
if #link.save
render :show, status: :created
else
render_error
end
end
private
def link_params
params.require(:resource).permit(:title, :description, :category, :image, :type, :url, :collection_id, :user_id, :section_id)
end
def render_error
render json: { errors: #resource.errors.full_messages },
status: :unprocessable_entity
end
end
Models
User
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
acts_as_token_authenticatable
has_many :collections, dependent: :destroy
has_many :sections, through: :collections, dependent: :destroy
has_many :links, through: :sections, dependent: :destroy
mount_uploader :image, PhotoUploader
end
Collection
class Collection < ApplicationRecord
belongs_to :user
has_many :sections, dependent: :destroy
has_many :links, through: :sections, dependent: :destroy
mount_uploader :image, PhotoUploader
end
Section
class Section < ApplicationRecord
belongs_to :collection
has_many :links, dependent: :destroy
end
Link
class Link < ApplicationRecord
belongs_to :section
end
Is this the correct way to set up the relationships and can someone help me understand what I am missing?
You can't do
#link.user_id = current_user
You could (instead) do...
#link.user_id = current_user.id
Or more elegantly...
#link.user = current_user
Which assumes you will define the relationship in the model
class Link < ApplicationRecord
belongs_to :section
belongs_to :user
end
But as Andrew Schwartz points out in the comments, it may have been a design mistake to add the field user_id to the links table. You have in the User model has_many :links, through: :sections, dependent: :destroy which does not use any user_id field in the link record. It uses the user_id field in the collections table
Just adding user_id to the links table will NOT mean that link will be returned when you do my_user.links ... it won't be.
Since you're passing a section_id in the link_params that is enough to create the link to the user, so just write a migration to remove the user_id field. If you want to be able to see the associated user from the link, do...
class Link < ApplicationRecord
belongs_to :section
has_one :collection, through: :section
has_one :user, through: :collection
end
and that will let you do my_link.user to retrieve the link's user.
My app has posts which have comments. This is the functionality I would like: A user sees the comment activity on the post he has created AND a commenter sees comment activity on the posts he has commented on.
My models:
class Post < ActiveRecord::Base
belongs_to :user
belongs_to :course
has_many :comments, dependent: :destroy
end
class Comment < ActiveRecord::Base
include PublicActivity::Model
tracked except: :update, owner: ->(controller, model) { controller && controller.current_user }
belongs_to :post
belongs_to :user
end
And the Activities controller:
class ActivitiesController < ApplicationController
def index
#activities = PublicActivity::Activity.order("created_at desc")
end
end
And the Activities index view:
<% #activities.each do |activity| %>
<div class="activity">
<%= link_to activity.owner.username, activity.owner if activity.owner %>
added comment to <%= link_to activity.trackable.post.title, activity.trackable.post %>
</div>
<% end %>
Thanks!
I'm afraid the PublicActivity gem is not designed to do this. It is meant to create one activity when one activity happens. In your case you need to create possible many notification records (1/user) if an activity happens. We had the same problem at my work and we decided to create a Notification model that is similar to the PublicActivity implementation.
class User < ActiveRecord::Base
has_many :notifications, foreign_key: :notified_user_id, dependent: :destroy
end
class Comment < ActiveRecord::Base
# maybe it would be better to name it as inverse_notifications
has_many :notifications, as: :trackable, dependent: :destroy
end
class Notification < ActiveRecord::Base
belongs_to :trackable, polymorphic: true
belongs_to :acting_user, class_name: "User"
belongs_to :notified_user, class_name: "User"
validates_presence_of :trackable, :notified_user, :key
scope :unread, -> { where("read_at IS NULL") }
end
This allows you to create 2 types of notifications when a comment is created:
one for the owner with key: "post.commented"
many for the commenters with key: "comment.created"
And it is possible to set the read_at attribute if the user has seen it, so you can add different style to them on the frontend.
I am new to rails and i keep getting this error
Couldn't find User without an ID
from:
class UserController < ApplicationController
def show
#user = User.find(params[:id])
end
end
this is what i have;
model/user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
validates :name, presence: true
validates :email, presence: true
has_many :listings, dependent: :destroy
has_many :purchasing, class_name: "Transaction", foreign_key: "buyer_id", dependent: :destroy
has_many :sell, class_name: "Transaction", foreign_key: "seller_id", dependent: :destroy
has_many :purchased, class_name: "Archive", foreign_key: "buyer_id", dependent: :destroy
has_many :sales, class_name: "Archive", foreign_key: "seller_id", dependent: :destroy
has_many :selling_rooms, class_name: "Room", foreign_key: "seller_id", dependent: :destroy
has_many :buying_room, class_name: "Room", foreign_key: "buyer_id", dependent: :destroy
def can_buy?(listing_price)
if self.points >= listing_price
true
else
false
end
end
def withdraw(listing_price)
self.points -= listing_price
end
def purchasing_list
purchasing.includes(:seller, :listing)
end
def purchased_list
purchased.includes(:seller, :listing)
end
def sell_list
sell.includes(:seller, :listing)
end
def sales_list
sales.includes(:seller, :listing)
end
end
resources
resources :users
I looked around but all i could find was something saying that it is looking for a resource that doesn't exist.
It seems that params[:id] not present.
first try to check with putting in
class UserController < ApplicationController
def show
logger"-----#{params[:id]}---"
#user = User.find(params[:id])
end
end
if its empty then pass id from the link from where you getting this error
ex. localhost:3000/users/1
here params[:id] == 1 must be
Some where in your form which redirects you to the users show page you should send the id or send the object itself.
<%= link_to 'Show', user_path(user) %>
or
<%= link_to 'Show', user_path(user.id) %>
Please check your params, As I know you are getting params[:id] = nil.
Try to pass :id in your params or you can check it by hard-coding it.
Check yo console!
In the parameters that are sent through in the request that is blowing up, have a look at exactly what the id your sending through is. Is it a user_id? is it an id? Your controller is expecting an id so make sure you are passing it one.
If you're passing an entire object you will need to specify. Eg. If you're passing through a user you'll need to pass through a user.id instead because your controller is expecting an ID which is typically a number. user will give the whole object, user.id will give just the number value, which is the ID in this case. Then with that number the controller action can find the relevant user in the database.
I'm trying to build a method that pulls an array of arrays, much like nested loops in the view.
I am trying to build a method on my User model that does this:
#past_parties = User.parties
<%= #past_parties.each do |past_party| %>
<%= past_party.guests("email").uniq.each do |guest| %>
<%= guest.name %> <%= guest.email %>
<% end %>
<% end %>
These are my models:
class User < ActiveRecord::Base
has_many :hosts, dependent: :destroy
has_many :parties, through: :hosts
def past_guests
self.parties.guests
end
end
class Host < ActiveRecord::Base
belongs_to :user
has_many :parties, dependent: :destroy
has_many :guests, through: :parties
end
class Party < ActiveRecord::Base
belongs_to :host
has_many :guests, dependent: :destroy
end
class Guest < ActiveRecord::Base
belongs_to :party
end
I can get the loop to work in the view, but when I try to build it as a method (so I can call current_user.past_guests, if current_user is an instance of User.), I get this error
undefined method `guests' for #<ActiveRecord::Associations::CollectionProxy []>
How do I get all of the guests that a user has ever invited without building the loop in the view?
The problem is that you're trying to access an array from another array:
self.parties.guests
self.parties returns an #<ActiveRecord::Associations::CollectionProxy []>, so if you want to get the guests of the parties you have to loop over the elements.
But since you want only the guests, you can simply change your user class to:
class User < ActiveRecord::Base
has_many :hosts, dependent: :destroy
has_many :parties, through: :hosts
has_many :guests, through: :parties
# Call your guests
def past_guests
self.guests
end
end
Each party is going to have collection of guests. You need to do this in your method definition:
def past_guests
self.parties.collect(&:guests)
end