rails project#index don't display user projects - Many to Many association - ruby-on-rails

I try to create app like this : An user can create a project, and invite many members to this project. Right now, I try to display all projects created by the user with projects#index method on projects_controller.rb. But, on browser, on /projects links, I don't have any errors, and don't have projects.
Here is my code,
projects_controller.rb :
def index
#user = current_user
#projects = #user.projects
end
def create
#project = Project.new(project_params)
#project.user_id = current_user.id
if #project.save
flash[:success] = "successfully created project"
redirect_to projects_path
else
render 'new'
end
end
Here is models (user, project, membership, invite) :
class Invite < ApplicationRecord
belongs_to :project
belongs_to :sender, :class_name => 'User'
belongs_to :recipient, :class_name => 'User'
before_create :generate_token
before_save :check_user_existence
def generate_token
self.token = Digest::SHA1.hexdigest([self.project_id, Time.now, rand].join)
end
def check_user_existence
recipient = User.find_by_email(email)
if recipient
self.recipient_id = recipient.id
end
end
end
class User < ApplicationRecord
has_many :memberships
has_many :projects, through: :memberships
has_many :invitations, :class_name => 'Invite', :foreign_key => 'recipient_id'
has_many :sent_invites, :class_name => 'Invite', :foreign_key => 'sender_id'
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
class Project < ApplicationRecord
has_many :memberships
has_many :users, through: :memberships
has_many :invites
end
class Membership < ApplicationRecord
belongs_to :user
belongs_to :project
end
And here is the view where I want to display user.projects :
<div class="container">
<h3> All your projects </h3>
<% #projects.each do |project| %>
<div class="project-card">
<div class="card-title">
<%= link_to project.title, project_path(project) %>
</div>
</div>
<% end %>
</div>
Maybe you want to see the schema :
ActiveRecord::Schema.define(version: 20161211133001) do
create_table "invites", force: :cascade do |t|
t.string "email"
t.integer "project_id"
t.integer "sender_id"
t.integer "recipient_id"
t.string "token"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "memberships", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.integer "project_id"
t.index ["project_id"], name: "index_memberships_on_project_id"
t.index ["user_id"], name: "index_memberships_on_user_id"
end
create_table "projects", force: :cascade do |t|
t.string "title"
t.integer "nb_team"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
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.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
end
Thank you !

Ok I fix it by writing this :
def index
#projects = Project.where(:user_id => current_user)
end
Maybe it will help !

Related

After being saved the foreign_key = nil - Solving error in db

I save the #booking with a user (called "booker"). Right after the #booking.save I can retrieve #booking.booker in the command line that display all the properties from the user (email, password, id, etc.). However After leaving the create method, impossible to retrieve it (for example from the show) : #booking.booker = nil .
I guess that commes from a mistake in my booking model : I have belongs_to and has_many_through. If the error comes from here, how to solve it without having to change all the db?
booking_controller.rb
class BookingsController < ApplicationController
before_action :set_booking, only: [:show, :edit, :update ]
before_action :set_booking_format, only: [:destroy ]
def index
end
def my_bookings
#bookings = BookingPolicy::Scope.new(current_user, Booking).scope.where(booker: current_user)
end
def show
authorize #booking
end
def new
#garden = Garden.find(params[:garden_id])
#booking = Booking.new
authorize #booking
end
def create
#garden = Garden.find params[:garden_id]
#booking = #garden.bookings.build(booker: current_user)
authorize #booking
if #booking.save
redirect_to garden_booking_path(#booking, current_user)
end
end
def update
end
private
def set_booking
#booking = Booking.find(params[:id])
end
def set_booking_format
#booking = Booking.find(params[:format])
end
def booking_params
params.require(:booking).permit(:garden_id, :booker_id, :date)
end
end
booking.rb
class Booking < ApplicationRecord
belongs_to :garden
belongs_to :booker, class_name: "User"
end
garden.rb
class Garden < ApplicationRecord
belongs_to :user
has_many :bookings, dependent: :destroy
end
user.rb
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :gardens
has_and_belongs_to_many :bookings
end
schema.rb
create_table "bookings", force: :cascade do |t|
t.date "date"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "garden_id"
t.integer "booker_id"
t.index ["garden_id"], name: "index_bookings_on_garden_id"
end
create_table "gardens", force: :cascade do |t|
t.string "title"
t.text "details"
t.integer "surface"
t.text "address"
t.bigint "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "availabilities"
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.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "admin", default: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
add_foreign_key "bookings", "gardens"
end
In your model, user.rb:
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :gardens
has_and_belongs_to_many :bookings
end
The :bookings association should be has_many. You aren't using a join table.
See: https://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association
The belongs_to part of the habtm association is looking for a foreign key, which doesn't exist. You can retrieve #booking.booker before moving to a different controller action because you aren't hitting the database at all, you're just retrieving the instance variables' association.

has_many through association dependent error is still referenced in table users

Before I start, I should say I have already checked out Rails 5.1.: destroy records in "has_many: through" association with restriction and has_many through association dependent destroy under condition of who called destroy without results.
My app consist in USERS that has_one EMPRESA.
An EMPRESA may have several TAGS
A TAG may have several EMPRESAS (To do this I have used has_many :through)
My case: I got this screen error:
And I know the origin of this error is because I'm trying to destroy items with pending references. But I can't identify th issue.
By looking at server console I can guess the problem involve empresa, tag, and tagging.
Models involved
class Empresa < ApplicationRecord
skip_callback :validate, after: :create
after_initialize :set_default_plan, :if => :new_record?
attr_accessor :tag_list
enum plan: [:noplan, :basic, :plus, :premium]
belongs_to :user
belongs_to :category, optional: true
has_many :promos, dependent: :destroy
has_many :taggings, dependent: :destroy
has_many :tags, through: :taggings
mount_uploader :logo, LogoUploader
mount_uploaders :fotos, FotosUploader
def tag_list
tags.join(", ")
end
def tag_list=(names)
tag_names = names.split(",").collect {|str| str.strip.downcase}.uniq
new_or_existing_tags = tag_names.collect {|tag_name| Tag.find_or_create_by(name: tag_name)}
self.tags = new_or_existing_tags
end
def set_default_plan
self.plan ||= :noplan
end
end
class Tag < ApplicationRecord
has_many :empresas, through: :taggings
has_many :taggings, dependent: :destroy
def to_s
name
end
end
class Tagging < ApplicationRecord
belongs_to :empresa
belongs_to :tag
end
class Category < ApplicationRecord
validates :name, presence: true, length:{ minimum: 3 }, uniqueness: true
has_many :empresas, dependent: :nullify
end
class User < ApplicationRecord
enum role: [:user, :editor, :admin, :superadmin]
after_initialize :set_default_role, :if => :new_record?
has_one :empresa, dependent: :destroy
has_many :incidents, dependent: :destroy
has_many :comments, dependent: :destroy
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
def set_default_role
self.role ||= :user
end
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
schema.rb (irrelevant tables removed)
ActiveRecord::Schema.define(version: 20180531033550) do
enable_extension "plpgsql"
create_table "empresas", force: :cascade do |t|
t.string "logo"
t.string "name"
t.text "description"
t.text "excerpt"
t.string "address"
t.string "web"
t.string "email"
t.string "tel"
t.string "video"
t.json "fotos"
t.integer "plan", default: 0
t.float "mlon"
t.float "mlat"
t.string "schedule0"
t.string "schedule1"
t.string "schedule2"
t.string "schedule3"
t.string "schedule4"
t.string "schedule5"
t.string "schedule6"
t.string "schedule7"
t.string "schedule8"
t.string "schedule9"
t.string "schedule10"
t.string "schedule11"
t.string "schedule12"
t.string "schedule13"
t.string "schedule14"
t.string "schedule15"
t.string "schedule16"
t.string "schedule17"
t.string "schedule18"
t.string "schedule19"
t.string "schedule20"
t.string "schedule21"
t.string "schedule22"
t.string "schedule23"
t.string "schedule24"
t.string "schedule25"
t.string "schedule26"
t.string "schedule27"
t.integer "tag_id"
t.integer "offer_id"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "category_id"
t.index ["category_id"], name: "index_empresas_on_category_id", using: :btree
end
create_table "taggings", force: :cascade do |t|
t.integer "empresa_id"
t.integer "tag_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["empresa_id"], name: "index_taggings_on_empresa_id", using: :btree
t.index ["tag_id"], name: "index_taggings_on_tag_id", using: :btree
end
create_table "tags", force: :cascade do |t|
t.string "name"
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.integer "creditos", default: 0, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "empresa_id"
t.integer "role"
t.string "first_name"
t.string "last_name"
t.date "birthdate"
t.string "dni"
t.string "phone"
t.string "address"
t.string "gender"
t.index ["email"], name: "index_users_on_email", unique: true, using: :btree
t.index ["empresa_id"], name: "index_users_on_empresa_id", using: :btree
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
end
add_foreign_key "comments", "incidents"
add_foreign_key "comments", "users"
add_foreign_key "incidents", "users"
add_foreign_key "promos", "empresas"
add_foreign_key "taggings", "empresas"
add_foreign_key "taggings", "tags"
add_foreign_key "users", "empresas"
end
You do not need empresa_id in users.
Remove the referential integrity and column via:
rails g migration remove_constraint_from_users
Edit the newly created migration file to add the following in def change block
def change
remove_foreign_key :users, :empresas
remove_column :users, :empresa_id
end

crossing borders of tables: language role

I'm new to development, and have spent the last 12 hours (literally) trying to figure out this error message - I'm giving up for the night, but not before a quick cry for help to stackoverflow.
I have this form:
<h2>Select from the language options below (or, <%= button_to "Login", 'users/login', method: :get %></h2>
<%= form_for #language_role do |f| %>
<div id="input">
<h3>I want to learn:</h3><%= select_tag(:language_id, options_from_collection_for_select(Language.all, :id, :lang_name)) %>
</div>
<div>
<p><%= f.submit "Start learning" %></p>
</div>
<% end %>
which is giving me this error message, highlighting the line #language_role = current_user.language_roles.build : "undefined method `language_roles' for nil:NilClass"
I have three tables:
create_table "language_roles", force: :cascade do |t|
t.integer "language_id"
t.boolean "is_active"
t.boolean "is_teacher"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.index ["user_id"], name: "index_language_roles_on_user_id"
end
create_table "languages", force: :cascade do |t|
t.string "lang_name"
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.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
The language_roles table is meant to allow a user to have many languages, as well as many roles within that language. Here are my class definitions:
class LanguageRole < ApplicationRecord
belongs_to :languages
belongs_to :users
end
class Language < ApplicationRecord
has_many :language_roles
has_many :users, :through => :language_roles
end
class User < ApplicationRecord
has_many :language_roles
has_many :languages, :through => :language_roles
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
My root path goes to 'home#index', where the user is supposed to pick a language if current_user.language_roles is empty. As such, I put this code in my home controller and language_roles controller:
class HomeController < ApplicationController
def index
#language_role = current_user.language_roles.build
end
end
class LanguageRolesController < ApplicationController
def create
#language_role = current_user.language_roles.build(language_role_params)
if #language_role.save
redirect_to root_path
else
redirect_to :back
end
end
private
def language_role_params
params.permit(:language_id)
end
end
What in the hell is the problem?? I assume I need to instantiate the variable somehow, but I'm not sure how.
Thanks,
Michael
There is a typo in your LanguageRole Model:
LanguageRole < ApplicationRecord
belongs_to :languages
belongs_to :users
end
should be
LanguageRole < ApplicationRecord
belongs_to :language
belongs_to :user
end
belongs_to associations must use the singular term.
The name of the other model is pluralized when declaring a has_many association.
Ref: http://guides.rubyonrails.org/association_basics.html
Your current_user is not defines it seems. You can install a gem called 'pry-rails' and debug your way out of this situation and any other in future. Here's a tutorial how to use it Railscasts #280
In your LanguageRole model you defined like belongs_to :users. But it should be belongs_to :user.
Your model look like ...
LanguageRole < ApplicationRecord
belongs_to :languages
belongs_to :users
end
Which should be something like
LanguageRole < ApplicationRecord
belongs_to :language
belongs_to :user
end

NoMethodError in Account::PostsController#index

I'm the newbie, my rails version is 4.2.0 and I install three gem devise, cancancan, rolify. When I sign up success, I got this message
NoMethodError in Account::PostsController#index
undefined method `role' for #<User:0x007fd84c2afba8>
def admin?
self.role.name == "admin"
end
end
I guess the problem is users, roles the connection is miss. And I try to modify my user.rb but not work.
This is my app/models/ability.rb code
class Ability
include CanCan::Ability
def initialize(user)
if user.admin?
can :manage, :all
else
can :update, Post do |post|
post.user == user
end
can :destroy, Post do |post|
post.user == user
end
can :create, Post
end
end
end
app/models/user.rb
class User < ActiveRecord::Base
has_many :posts
############################################################
# not work
# belongs_to :users_roles
# has_and_belongs_to_many :roles, :join_tabe => :users_roles
# has_one :users_role
############################################################
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
def admin?
self.role.name == "admin"
end
end
app/models/role.rb
class Role < ActiveRecord::Base
has_and_belongs_to_many :users, :join_table => :users_roles
belongs_to :resource, :polymorphic => true
validates :resource_type,
:inclusion => { :in => Rolify.resource_types },
:allow_nil => true
scopify
end
When I sign up I will add a role to first sign up user, this is my application_controller.rb
def after_sign_in_path_for(resource)
if resource.is_a?(User)
if User.count == 1
resource.add_role 'admin'
else
resource.add_role 'normal'
end
resource
end
root_path
end
schema.rb
ActiveRecord::Schema.define(version: 20160225105659) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "ckeditor_assets", force: :cascade do |t|
t.string "data_file_name", null: false
t.string "data_content_type"
t.integer "data_file_size"
t.integer "assetable_id"
t.string "assetable_type", limit: 30
t.string "type", limit: 30
t.integer "width"
t.integer "height"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "ckeditor_assets", ["assetable_type", "assetable_id"], name: "idx_ckeditor_assetable", using: :btree
add_index "ckeditor_assets", ["assetable_type", "type", "assetable_id"], name: "idx_ckeditor_assetable_type", using: :btree
create_table "posts", force: :cascade do |t|
t.string "title"
t.text "content"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
end
create_table "roles", force: :cascade do |t|
t.string "name"
t.integer "resource_id"
t.string "resource_type"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "roles", ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id", using: :btree
add_index "roles", ["name"], name: "index_roles_on_name", using: :btree
create_table "travel_events", force: :cascade do |t|
t.string "title"
t.datetime "start_date"
t.datetime "end_date"
t.text "note"
t.integer "travel_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "travels", force: :cascade do |t|
t.string "title"
t.datetime "start_date"
t.datetime "end_date"
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"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
create_table "users_roles", id: false, force: :cascade do |t|
t.integer "user_id"
t.integer "role_id"
end
add_index "users_roles", ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id", using: :btree
end
I think you forgot to add
has_one :users_role
in user.rb
I find the answer, but I'm not sure the question is table's relationship.
I remove my user.rb's admin method
user.rb
class User < ActiveRecord::Base
rolify
has_many :posts
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# def admin?
# self.role.name == "admin"
# end
end
And modify ability.rb
ability.rb
class Ability
include CanCan::Ability
def initialize(user)
# if user.admin?
if user.has_role?(:admin) # modify this line
can :manage, :all
else
can :update, Post do |post|
post.user == user
end
can :destroy, Post do |post|
post.user == user
end
can :create, Post
can :read, Post
end
end
end

How do I add a posted by 'user.email' to my app index?

So, the index I'm referring to is in songs#index.html.erb.
I'd like to add a line like this:
posted by <%= song.user.email %> <%= time_ago_in_words(song.created_at) + " ago" %>
which at the moment is returning:
undefined method `email' for nil:NilClass
Song.rb snippit
class Song < ActiveRecord::Base
extend FriendlyId
friendly_id :title, use: :slugged
acts_as_voteable
belongs_to :user, class_name: User, foreign_key: :user_id
has_many :comments, :dependent => :destroy
has_many :genre_songs
has_many :genres, through: :genre_songs
User.rb snippit
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :omniauthable,
:recoverable, :rememberable, :trackable, :validatable
has_many :songs
has_many :comments
schema snippits
create_table "users", id: false, force: true do |t|
t.integer "id", null: false
t.string "email", default: ""
t.string "encrypted_password", default: ""
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0
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"
t.datetime "updated_at"
t.boolean "admin"
t.string "provider"
t.string "uid", null: false
t.string "username"
end
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
create_table "songs", force: true do |t|
t.string "title"
t.string "artist"
t.text "url"
t.string "track_file_name"
t.string "track_content_type"
t.integer "track_file_size"
t.datetime "track_updated_at"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "plusminus"
t.string "slug"
end
add_index "songs", ["slug"], name: "index_songs_on_slug", unique: true, using: :btree
It seems one of your songs you list in index doesn't have its associated user, so the song.user returns nil.
To avoid this you should validate presence of user in Song model, or check if user exists in view, like this:
<% if song.user %>
posted by <%= song.user.email %> <%= time_ago_in_words(song.created_at) + " ago" %>
<% end %>
The approach depends on your application logic.

Resources