Recently I installed devise_invitable to my application, I'm currently trying to figure out how to display the of the inviter.
In my view I'm trying to get the fullname of the user who sent an invite.
I tried the following:
Example.html.erb
<% #users.each do |user| %>
<%= user.fullname %> # Gives me the name of the user
<%= user.invited_by %> # Gives me ActiveRecord Association
<%= user.invited_by.fullname %> # Gives me an undefined method error
<% end %>
I would like to achieve this <%= user.invited_by.fullname %> is this possible?
Migration for devise_invitable
class DeviseInvitableAddToUsers < ActiveRecord::Migration[5.2]
def up
change_table :users do |t|
t.string :invitation_token
t.datetime :invitation_created_at
t.datetime :invitation_sent_at
t.datetime :invitation_accepted_at
t.integer :invitation_limit
t.references :invited_by, polymorphic: true
t.integer :invitations_count, default: 0
t.index :invitations_count
t.index :invitation_token, unique: true # for invitable
t.index :invited_by_id
end
end
def down
change_table :users do |t|
t.remove_references :invited_by, polymorphic: true
t.remove :invitations_count, :invitation_limit, :invitation_sent_at, :invitation_accepted_at, :invitation_token, :invitation_created_at
end
end
end
User Model
class User < ApplicationRecord
devise :invitable, :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:confirmable, :omniauthable
validates :fullname, presence: true, length: { minimum: 4 }
validates_acceptance_of :terms_of_service
has_many :services
has_many :reservations
has_many :articles
has_many :lists
end
My guess is that not all of your users are invited by someone, so you need to check if invited_by is present first:
<% #users.each do |user| %>
<%= user.fullname %>
<% if user.invited_by.present? %>
<%= user.invited_by %>
<%= user.invited_by.fullname %>
<% end %>
<% end %>
Also when you send the invitation be sure that you are passing which user is sending the invite, since this parameter is optional:
User.invite!({:email => "new_user#example.com"}, current_user) # current_user will be set as invited_by
Related
class CreateJobs < ActiveRecord::Migration[5.1]
def change
create_table :jobs do |t|
t.string :title
t.text :description
t.string :company
t.integer :user_id
t.integer :company_id
t.timestamps
end
end
end
class CreateCompanies < ActiveRecord::Migration[5.1]
def change
create_table :companies do |t|
t.string :c_name
t.text :c_description
t.integer:user_id
t.timestamps
end
end
end
# Models
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :companies
has_many :jobs
end
class Job < ApplicationRecord
belongs_to :user
belongs_to :category
belongs_to :company
end
class Company < ApplicationRecord
belongs_to:user
has_many:jobs
end
# Jobs controller
def show
end
def new
#job = current_user.jobs.build
end
def create
job_attrs = jobs_params.except(:company)
job_attrs[:company] = Company.find_by(id: jobs_params[:company])
#job = current_user.jobs.build(job_attrs)
if #job.save
flash[:success]= "success"
redirect_to #job
else
flash[:error]=#job.errors.full_messages
render "new"
end
end
def jobs_params
params.require(:job).permit(:title, :description, :company, :category_id, :image,:jobclosedate,:company_id)
end
this is the views/jobs/_form
<%= simple_form_for(#job,validation:true ,html: { mutlipart: true, class: 'form-horizontal'}) do |f| %>
<%= f.input :title, label: "Job Title", input_html: { class: "form-control"}%>
<%= f.input :description, label: "Job Description", input_html: { class: "form-control" }%>
<%= f.input :company, label: "Your Company", input_html: { class: "form-control" }%>
<%= f.collection_select :category_id,Category.all, :id, :name, {promt: "Choose a category" }%>
When I try to create a job, it will show in views/jobs/_form.html.erb
"Company must exist" (job/_form will not get the company name from company module )
company should populate automatically in the views/jobs/_form.html.erb, it will not automatically populated and it'show company mush exit
I want to create a Rails app that allows "users" to follow other users. I am semi-new to more complex relationships and am attempting to set up has_many through for the first time. I want friends to be able to follow other users.
Here is my join table:
class Following < ApplicationRecord
belongs_to :user
belongs_to :follower, class_name: "User"
end
Here is my users table:
class User < ApplicationRecord
has_many :followings
has_many :followers, through: :followings
end
Here is my schema:
create_table "followings", force: :cascade do |t|
t.integer "user_id"
t.integer "follower_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
I don't know how to set up a form to actually create the relationship. In a users view, I have this, but it doesn't work.
<%= form_for #following do |f| %>
<%= f.hidden_field :follower_id, :value => #user %>
<%= f.select :user_id, #users.collect { |u| [u.name, u.id] } %>
<%= f.submit %>
<% end %>
As I said, I am very new to this type of relationship. I need help. I don't know how to link records through a form.
I am following this tutorial: https://teamtreehouse.com/library/what-is-a-hasmany-through-association-in-ruby-on-rails
I am assuming you have a current_user method that returns the logged in user - like what Devise provides. If not you need to setup authentication first.
Create a nested route:
# config/routes.rb
resources :users, only: [] do
resources :followings, only: [:create, :destroy], shallow: true
end
Add a validation to Following to avoid duplicates:
class Following < ApplicationRecord
belongs_to :user
belongs_to :follower, class_name: "User"
validates_uniqueness_of :user_id, scope: 'follower_id'
end
Add a utility method to User to see if he is following another user:
class User < ApplicationRecord
has_many :followings
has_many :followers, through: :followings
def following?(user)
followings.exist?(user: user)
end
def find_following(user)
followings.find_by(user: user)
end
end
We can then add Follow and Unfollow buttons (they are actually forms) to the /users/show.html.erb view.
<% if current_user.following?(#user) %>
<%= button_to "Unfollow", current_user.find_following(#user), method: :delete %>
<% else %>
<%= button_to "Follow", [#user, #user.followings.new] %>
<% end %>
Note that we don't need any form params since we are using a nested route (POST /users/:user_id/followings) to pass the user id (who gets followed) and we are getting the current user from the session.
We can then setup our controller:
class FollowingsController < ApplicationController
# POST /users/:user_id/followings
def create
#user = User.find(params[:user_id])
#following = Following.new(user: #user, follower: current_user)
if #following.save
redirect_to #user, success: "You are now following #{ #user.name }"
else
redirect_to #user, error: "Could not create following"
end
end
# DELETE /followings/:id
def destroy
#following = Following.find(params[:id])
#following.destroy
redirect_to #following.user, success: "You are no longer following #{ #user.name }"
end
end
I have three models: user, firm and revenue. I'd like to join the firm and revenue models, in order to publish the joined model results. Could someone please point me in the right direction on how to go about joining these tables and publish the results? Note, firm and revenue model can be joined through a unique_id number. Here is some of my code:
Revenue Model
class Revenue < ActiveRecord::Base
belongs_to :user
def self.import(file)
CSV.foreach(file.path, headers: true) do |row|
Revenue.create! row.to_hash
end
end
end
Firm Model
class Firm < ActiveRecord::Base
belongs_to :user
def self.import(file)
CSV.foreach(file.path, headers: true) do |row|
Firm.create! row.to_hash
end
end
end
User Model
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
before_save { self.email = email.downcase }
has_many :revenues
has_many :firms
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:session_limitable, :confirmable
validates :name, :lastname, :industry, :company, :title, :address, :state, :city, :zip, presence: true
validates :phone, presence: true, length: { maximum: 11 }
end
Revenue DB
class CreateRevenues < ActiveRecord::Migration
def change
create_table :revenues do |t|
t.integer :unique_id
t.integer :revenue
t.integer :profit
t.references :user, index: true, foreign_key: true
t.timestamps null: false
end
end
end
Firm DB
class CreateFirms < ActiveRecord::Migration
def change
create_table :firms do |t|
t.integer :unique_id
t.string :name
t.string :state
t.string :city
t.references :user, index: true, foreign_key: true
t.timestamps null: false
end
end
end
View
<h2>Firm Data</h2>
<body>
<table>
<tr>
<th>unique_id</th>
<th>name</th>
<th>state</th>
<th>city</th>
</tr>
<body>
<% #firms.each do |firm| %>
<tr>
<td><%= firm.unique_id %> </td>
<td><%= firm.name %> </td>
<td><%= firm.state %> </td>
<td><%= firm.city %> </td>
<tr>
<% end %>
</table>
</body>
<h2>Revenue Data</h2>
<body>
<table>
<tr>
<th>unique_id</th>
<th>revenue</th>
<th>profit</th>
</tr>
<body>
<% #revenues.each do |rev| %>
<tr>
<td><%= rev.unique_id %> </td>
<td><%= rev.revenue %> </td>
<td><%= rev.profit %> </td>
<tr>
<% end %>
</table>
</body>
As per your question and comments it looks right to me to set up relationships as follow:
A user has_many firms (companies). A firm has_one revenue. A user has_many revenues through firms.
# app/models/user.rb
class User < ActiveRecord::Base
has_many :firms
has_many :revenues, through :firms
end
# app/models/firm.rb
class Firm < ActiveRecord::Base
has_one :revenue
end
# app/models/revenue.rb
class Revenue < ActiveRecord::Base
belongs_to :firm
end
Instead of storing a unique_id in both firms and revenues tables, it would be better to use a foreign_key in revenues, like firm_id.
The corresponding migrations are:
class CreateFirm < ActiveRecord::Migration
def change
create_table :firm do |t|
t.string :name
t.string :state
t.string :city
t.timestamps null: false
end
end
end
class CreateRevenue < ActiveRecord::Migration
def change
create_table :firm do |t|
t.belongs_to :firm, index: true
t.integer :revenue
t.integer :profit
t.timestamps null: false
end
end
end
This will enable you to use, for example, firm.revenue.profit to display the value of profit in the app/views/firms/show.html.erb view.
Looking at your models and migrations syntax it seems you are not using Rails 5. You can find Rails 4.2 docs about the has_one relationship here.
I have this problem in rails..
It says undefined method email for #<UserInfo:0xc0ac77c>
I debug this several times i could not trace the error.
here is the sample code i have.
user_infos_controller.erb
class UserInfosController < ApplicationController
before_action :check_user_profile, only: :index
def index
#user = User.find(current_user.id)
puts #user
end
def new
#user_info = current_user.build_user_info
end
def show
#user = User.find(current_user)
end
def create
#user_info = UserInfo.create(
user_id: current_user.id,
fname: params[:user_info][:fname],
lname: params[:user_info][:lname],
bday: params[:user_info][:bday],
address: params[:user_info][:address],
picture: params[:user_info][:picture])
#if #user_info.save
#redirect_to user_infos
#else
#render new_user_info_path
#end
end
private
def profile_params
params.require(:user_info).permit(:fname, :lname, :bday, :address, :picture)
end
private
def check_user_profile
user = User.find(current_user)
if !user.user_info
redirect_to new_user_info_path
end
end
end
new.html.erb
<%= simple_form_for #user_info, html: { multipart: true } do |f| %>
<% if #user_info.errors.any? %>
<h2><%= pluralize(#user_info.errors.count, "error") %> Prevented this User from saving </h2>
<ul>
<% #user_info.errors.full_messages.each do |mg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
<div class="form-group">
<%= f.input :picture, input_html: { class: "form-control"} %>
</div>
<div class="form-group">
<%= f.input :fname, input_html: { class: "form-control"} %>
</div>
<div class="form-group">
<%= f.input :lname, input_html: { class: "form-control"} %>
</div>
<div class="form-group">
<%= f.input :address, input_html: { class: "form-control"} %>
</div>
<div class="form-group">
<%= f.date_field :bday, input_html: { class: "form-control"} %>
</div>
<div class="form-group">
<button class="btn btn-primary pull-right" type="submit">Save</button>
</div>
<% end %>
This is for the user database
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
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
## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at
# t.datetime :confirmation_sent_at
# t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
# t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
t.timestamps null: false
end
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
# add_index :users, :confirmation_token, unique: true
# add_index :users, :unlock_token, unique: true
end
end
And this is for user_infos database
class CreateUserInfos < ActiveRecord::Migration
def change
create_table :user_infos do |t|
t.string :fname
t.string :lname
t.date :bday
t.string :address
t.timestamps null: false
end
end
end
class AddAttachmentPictureToUserInfos < ActiveRecord::Migration
def self.up
change_table :user_infos do |t|
t.attachment :picture
end
end
def self.down
remove_attachment :user_infos, :picture
end
end
rails console
Started POST "/user_infos" for 127.0.0.1 at 2015-06-16 13:44:14 +0800
Processing by UserInfosController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"ig6pSrP9EV7ivQ3DRG/XPcwSQmr8oRhX+4YUtuxxqn/71ViwodxX06IMaQrzEQOWvOEjohAB1suFhubz0+cAJw==", "user_info"=>{"fname"=>"das", "lname"=>"dasa", "address"=>"dsasd", "bday"=>"2015-06-16"}}
User Load (1.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 3]]
(0.2ms) BEGIN
(2.8ms) ROLLBACK
Completed 500 Internal Server Error in 148ms (ActiveRecord: 14.0ms)
NoMethodError (undefined method `email' for #<UserInfo:0xbcaa624>):
app/controllers/user_infos_controller.rb:19:in `create'
Rendered /home/allanprog/.rvm/gems/ruby-2.2.1/gems/actionpack-4.2.1/lib/action_dispatch/middleware/templates/rescues/_source.erb (20.2ms)
Rendered /home/allanprog/.rvm/gems/ruby-2.2.1/gems/actionpack-4.2.1/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (11.9ms)
Rendered /home/allanprog/.rvm/gems/ruby-2.2.1/gems/actionpack-4.2.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (3.8ms)
Rendered /home/allanprog/.rvm/gems/ruby-2.2.1/gems/actionpack-4.2.1/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (108.5ms)
Cannot render console with content type multipart/form-dataAllowed content types: [#<Mime::Type:0xa39d5f0 #synonyms=["application/xhtml+xml"], #symbol=:html, #string="text/html">, #<Mime::Type:0xa39d474 #synonyms=[], #symbol=:text, #string="text/plain">, #<Mime::Type:0xa38b65c #synonyms=[], #symbol=:url_encoded_form, #string="application/x-www-form-urlencoded">]
user 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
has_many :pins
has_one :user_info
end
user_info model
class UserInfo < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :user
has_attached_file :picture, styles: { medium: "300x300>" }
validates_attachment_content_type :picture, :content_type => /\Aimage\/.*\Z/
end
Devise method in your models accepts some options to configure its modules.
So if you use devise on User model then you have to remove Devise methods from UserInfo model which is below
Remove this from UserInfo
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
For configuring Devise for multiple models have look at following documentation link
https://github.com/plataformatec/devise
Hopefully this will help.
I don't see any reason for getting NoMethodError (undefined method 'email' for #<UserInfo:0xbcaa624>) error, but 1 issue I can see is :
In create method of UserInfosController you have written :
#user_info = UserInfo.create(
user_id: current_user.id,
fname: params[:user_info][:fname],
lname: params[:user_info][:lname],
bday: params[:user_info][:bday],
address: params[:user_info][:address],
picture: params[:user_info][:picture])
but in user_infos table you haven't added the column for user_id. You should add the column user_id to user_infos table through migration like this :
class AddUserIdToUserInfos < ActiveRecord::Migration
def self.up
change_table :user_infos do |t|
t.references :user, foreign_key: true, index:true
end
end
def self.down
t.remove_references(:user)
end
end
I have the following models with associations as given below:-
class Comment < ActiveRecord::Base
belongs_to :post
belongs_to :user
end
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments
end
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me
has_many :posts
has_many :comments
end
But when I try to access's comment's user details I GET NO METHOD ERROR :(.
The error displayed in browser is as below:-
undefined method `email' for nil:NilClass
1: <p>
2: <% #post.comments.each do |comment| %>
3: <b>Comment written by:</b> <%= comment.user.email %><br />
4: <%= comment.body %><br />
5: <% end %>
6:
My schema is as below:-
create_table "comments", :force => true do |t|
t.integer "post_id"
t.integer "user_id"
t.text "body"
.... truncated
end
create_table "posts", :force => true do |t|
t.integer "user_id"
t.integer "sell_or_buy"
t.string "title"
t.text "body"
.... truncated
end
create_table "users", :force => true do |t|
t.string "email", :default => "", :null => false
t.string "encrypted_password", :limit => 128, :default => "", :null => false
.... truncated
end
My comments create method is as follows:-
class CommentsController < ApplicationController
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(params[:comment])
#comment.user_id = current_user.id
redirect_to post_path(#post)
end
end
As you can see I used devise for user model .
Any idea of what I'm doing wrong?Please help me out !!!
I'm using Rails 3.0.1
I believe that you are not saving the #comment after assigning it's user_id. You're doing #comment.user_id = current_user.id, but this change is not reflected in the database.
You could do something like:
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.new(params[:comment])
#comment.user_id = current_user.id
#comment.save
redirect_to post_path(#post)
end