Rails: NoMethodError on creating has_one association with devise model - ruby-on-rails

I am a complete beginner in Rails as such and I am trying to build a page to add extra profile data once the user logs in.
I am using Devise for authentication purposes and that works fine. I get this error and I have been stuck here.
undefined method `profiles'
Can you please help?
Codes
profiles_controller.rb
class ProfilesController < ApplicationController
before_action :authenticate_user!, only: [:new, :create, :show]
def new
#profile = current_user.profiles.build
end
def create
#profile = current_user.profiles.build(profile_params)
if #profile.save
format.html {redirect_to #profile, notice: 'Post was successfully created.'}
else
format.html {render 'new'}
end
end
def show
#profile = current_user.profiles
end
private
def profile_params
params.require(:profile).permit(:content)
end
end
The error seems to be coming from these lines in particular
def new
#profile = current_user.profiles.build
end
Other codes for reference:
/views/profiles/new.html.erb
<h1>Profiles#new</h1>
<p>Find me in app/views/profiles/new.html.erb</p>
<h3>Welcome <%= current_user.email %></h3>
<%= form_for(#profile) do |f| %>
<div class="field">
<%= f.label :content %><br />
<%= f.text_field :text, autofocus: true %>
</div>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<%end%>
routes.rb
Rails.application.routes.draw do
get 'profiles/new'
get 'profiles/create'
get 'profiles/show'
get 'profiles/update'
get 'pages/home'
get 'pages/dashboard'
devise_for :users, controllers: { registrations: "registrations" }
resources :profiles
root 'pages#home'
devise_scope :user do
get "user_root", to: "page#dashboard"
end
end
models/user.rb
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_one :profile, dependent: :destroy
end
models/profile.rb
class Profile < ActiveRecord::Base
belongs_to :user
end

I just figured it out!
As the relationship is has_one, we should be using
def new
#profile = current_user.build_profile
end
instead of
def new
#profile = current_user.profiles.build
end
according to the documentation -
http://guides.rubyonrails.org/association_basics.html#has-one-association-reference

1) If your user must have many profiles. Set in your app/models/user.rb has_many :profiles
2) In your ProfilesController in new method instead of #profile = current_user.profiles use #profile = Profile.new
3) In your routes.rb delete
get 'profiles/new'
get 'profiles/create'
get 'profiles/show'
get 'profiles/update'
because you have already used resources :profiles
4) To stay with rules of DRY you can render form from a partial. Just add in views/profiles/_form.html.erb with the same content in your new.html.erb and after this you can delete everything im new.htm.erb and paste <%= render "form" %>. In future it will help you to render edit form if you want.
5) In your ProfilesController you can add method index with all profiles
def index
#profiles = Profile.all
end

You are trying to call an undefined relationship:
def new
#profile = current_user.profiles.build
end
has_one :profile
You should be calling:
def new
#profile = current_user.build_profile
end

Related

rails, voting on nested comments

Ruby on Rails. Getting various errors while trying to add a voting feature via the acts_as_votable gem on nested comments.
The acts_as_votable works with the posts, but not with the nested comments under the posts.
With :
<%= link_to "Like", like_post_comment_path(#post, #comment), method: :put do %>
<i class="fa fa-arrow-up" aria-hidden="true">Yes</i>
<%= #p.get_upvotes.size %>
<% end %>
I get the error:
No route matches {:action=>"upvote", :controller=>"comments", :id=>nil, :post_id=>"1"}, missing required keys: [:id]
With:
<%= link_to "Like", like_post_comment_path(#post, #comment.id), method: :put do %>
<i class="fa fa-arrow-up" aria-hidden="true">Yes</i>
<%= #p.get_upvotes.size %>
<% end %>
I get the error:
undefined method `id' for nil:NilClass
I have tried various combinations as the parameters. All produce an error.
My Comments controller:
class CommentsController < ApplicationController
before_action :find_post, only: [:upvote, :downvote, :create, :destroy, :edit, :update]
before_action :find_comment, only: [:upvote, :downvote :destroy, :update, :edit, :comment_owner ]
before_action :comment_owner, only: [:destroy, :edit, :update]
def new
#comment = Comment.new
#post = Post.new
end
def create
#comment = #post.comments.create(params[:comment].permit(:content))
#comment.user_id = current_user.id
#comment.save
if #comment.save
redirect_back(fallback_location: root_path)
else
render 'new'
end
end
def destroy
#comment.destroy
redirect_back(fallback_location: root_path)
end
def edit
#comment = Comment.find(params[:id])
#p = Post.find(params[:post_id])
end
def update
if #comment.update(params[:comment].permit(:content))
respond_to do |f|
if (#comment.save)
f.html { redirect_to "/explore", notice: "Comment edited!" }
elsif
f.html { redirect_to "/explore", notice: "Error: Your Comment is the same!." }
else
render 'edit'
#f.html { render 'edit'} ## Specify the format in which you are rendering "new" page
end
end
end
end
def upvote
#comment.upvote_from current_user
redirect_back(fallback_location: root_path)
end
def downvote
#comment.downvote_from current_user
redirect_back(fallback_location: root_path)
end
private
def find_post
#post = Post.find(params[:post_id])
end
def find_comment
#comment = #post.comments.find(params[:id])
end
def comment_owner
unless current_user.id == #comment.user_id
flash[:notice] = "You can't do that!"
redirect_back(fallback_location: root_path)
end
end
end
Comment model:
class Comment < ApplicationRecord
belongs_to :commentable, :polymorphic => true
belongs_to :user
acts_as_votable
# scope :desc
default_scope { order(created_at: :desc) }
end
Post model:
class Post < ApplicationRecord
belongs_to :user
has_many :comments, :as => :commentable
attr_accessor :post_id
acts_as_votable
validates :user_id, presence: true
validates :content, presence: true, length: { maximum: 100} # Questions are capped at 100 chars.
default_scope { order(cached_votes_score: :DESC) }
end
User model:
class User < ApplicationRecord
has_many :posts
has_many :comments, :as => :commentable
acts_as_voter
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :posts, dependent: :destroy
def user
user = User.find_by(params[:id])
end
Routes:
like_post_comment PUT /posts/:post_id/comments/:id/like(.:format) comments#upvote
dislike_post_comment PUT /posts/:post_id/comments/:id/dislike(.:format) comments#downvote

Model does not seem to be getting saved?

So I am using the devise gem to generate users for my web app. I have a Business model that is a has_one: association with my User. When I attempt to create a business when logged into my user it simply does not save it. Also when i use rails console in the terminal attempting to open up my Business model returns nil. In the view that is calling .business on the user shows nothing
Here is my business model
class Business < ActiveRecord::Base
belongs_to :user
end
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
validates :name, presence: true
has_many :posts, dependent: :destroy
has_one :business, dependent: :destroy
has_attached_file :avatar,
styles: { medium: "300x300#", thumb: "100x100#", post_pic: "44x44" },
default_url: "/images/:style/missing.png"
validates_attachment_content_type :avatar, content_type: /\Aimage\/.*\Z/
end
Business controller
class BusinessesController < ApplicationController
before_action :set_business, only: [:show, :edit, :update, :destroy]
def index
#businesses = Business.all
end
def show
end
def new
#business = current_user.build_business
end
def edit
end
def create
#business = current_user.build_business(business_params)
if #business.save
redirect_to #business, notice: 'Business was successfully created.'
else
render :new
end
end
def update
if #business.update(business_params)
redirect_to #business, notice: 'Business was successfully updated.'
else
render :edit
end
end
def destroy
#business.destroy
redirect_to businesses_url, notice: 'Business was successfully destroyed.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_business
#business = Business.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def business_params
params.require(:business).permit(:name, :desc, :avatar)
end
end
VIEW THAT CALLS THE BUSINESS
<div class="row">
<div class="col-md-7">
<div class="panel panel-default">
<div class="panel-body">
<%= image_tag current_user.business.avatar.url(:thumb), class:"img-thumbnail" %>
<%= current_user.business.name %>
<%= current_user.business.desc %>
<%= link_to 'create business', new_business_path, class:"pull-right" %>
</div>
</div>
</div>
</div>
Do you have a user_id column in your business table? It would look like this: t.integer "user_id"
Then, to directly associate the business with the user, in businesses_controller.rb I would write the new and create methods in that way:
def new
#business = current_user.businesses.new
end
def create
#business = current_user.businesses.new(business_params)
if #business.save
redirect_to #business, notice: 'Business was successfully created.'
else
render :new
end
end
Hope this helps.

Links redirecting to wrong view path

All links work well except for devise. If I try to click sign up or log in it takes me to the sign up/log in page, right?
From the URL it looks normal. localhost:3000/users/sign_up but the view is wrong. It's displaying the profile view instead of the devise sign up/log in view.
Routes code:
Rails.application.routes.draw do
resources :questions
get '/users/:id' => 'profile#profile'
devise_for :users
root 'home#index'
end
Profile controller:
class ProfileController < ApplicationController
def profile
end
end
User model:
class User < ActiveRecord::Base
has_many :questions
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
Question model
class Question < ActiveRecord::Base
belongs_to :user
end
It didn't do that at first, I think this bug happened when I edited the show.html.erb view in the questions folder.
Show code (question):
<% #questions.each do |q| %>
<% if user_signed_in? %>
<% if q.id == current_user.id %>
<%= link_to 'Edit', edit_question_path(#question) %>
<% end %>
<% end %>
<% end %>
Question controller:
class QuestionsController < ApplicationController
before_action :set_question, only: [:show, :edit, :update, :destroy]
respond_to :html
def index
#questions = Question.all
respond_with(#questions)
end
def show
#questions = Question.all
respond_with(#question)
end
def new
#question = Question.new
respond_with(#question)
end
def edit
end
def create
#question = Question.new(question_params)
#question.save
respond_with(#question)
end
def update
#question.update(question_params)
respond_with(#question)
end
def destroy
#question.destroy
respond_with(#question)
end
private
def set_question
#question = Question.find(params[:id])
end
def question_params
params.require(:question).permit(:title, :description, :image_url)
end
end
Try putting that get '/users/:id' => 'profile#profile' below the devise_for :users line.

Rails - nested model input data not appearing in "show" page

I am having trouble figuring out how to make some data collected through a nested model appear on the "show" page. I have a rails app with 3 models, a User model, a Project model, and a Team model. The model associations are as follows:
Project:-
class Project < ActiveRecord::Base
has_many :users, :through => :team
has_one :team, :dependent => :destroy
accepts_nested_attributes_for :team, allow_destroy: true
end
Team:-
class Team < ActiveRecord::Base
belongs_to :project
has_many :users
end
User:-
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_and_belongs_to_many :teams
end
Every project has one team, and every team consists of many users who are already saved in the database. What I would like to do exactly is to make it possible to select multiple existing users within the project form (through a nested form) and save them to a model called team. I managed to get the form working correctly, but im not sure how to go about saving the data collected to the team model, and then to make the group of users that were selected (the team) to appear in project's show page. Please help!
P.S I used the nested form gem to add multiple team members within the project's form.
Projects Show page:-
<%= bootstrap_nested_form_for(#project, :html => {:multipart => true}, layout: :horizontal) do |f| %>
<% f.fields_for :teams do |builder| %>
<% if builder.object.new_record? %>
<%= builder.collection_select :user, User.all, :id, :email, { prompt: "Please select", :selected => params[:user], label: "Employee" } %>
<% else %>
<%= builder.hidden_field :_destroy %>
<%= builder.link_to_remove "Remove" %>
<% end %>
<%= f.link_to_add "Add Team Member", :teams %>
<%= f.submit %>
<% end %>
projects controller:-
class ProjectsController < ApplicationController
before_action :set_project, only: [:show, :edit, :update, :destroy]
respond_to :html
def index
#projects = Project.all
respond_with(#projects)
end
def show
respond_with(#project)
end
def new
#project = Project.new
#project.pictures.build
#project.teams.build
respond_with(#project)
end
def edit
#project = Project.find(params[:id])
#project.pictures.build
#project.teams.build
end
def create
#project = Project.new(project_params)
if #project.save
flash[:notice] = "Successfully created project."
redirect_to #project
else
render :action => 'new'
end
end
def update
#project.update(project_params)
respond_with(#project)
end
def destroy
#project.destroy
respond_with(#project)
end
private
def set_project
#project = Project.find(params[:id])
end
def project_params
params.require(:project).permit(:id, :title, :description, :status, :phase, :location, :image, pictures_attributes: [:id, :image], teams_attributes: [:project_id, :user_id])
end
end

Rails - Nested form not showing on "show" page

I am having trouble figuring out how to make some data collected through a nested model appear on the "show" page. I have a rails app with 3 models, a User model, a Project model, and a Team model. The model associations are as follows:
Project:-
class Project < ActiveRecord::Base
has_many :users, :through => :team
has_one :team, :dependent => :destroy
accepts_nested_attributes_for :team, allow_destroy: true
end
Team:-
class Team < ActiveRecord::Base
belongs_to :project
has_many :users
end
User:-
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_and_belongs_to_many :teams
end
Every project has one team, and every team consists of many users who are already saved in the database. What I would like to do exactly is to make it possible to select multiple existing users within the Project form (through a nested form) and save them to a model called Team. I managed to get the form working correctly, but im not sure how to go about saving the data collected to the team model, and then to make the group of users that were selected (the team) to appear in project's show page, as there are 3 models involved. The Please help!
P.S I used the nested form gem to add multiple team members within the project's form.
Projects Show page:-
<%= bootstrap_nested_form_for(#project, :html => {:multipart => true}, layout: :horizontal) do |f| %>
<% f.fields_for :teams do |builder| %>
<% if builder.object.new_record? %>
<%= builder.collection_select :user, User.all, :id, :email, { prompt: "Please select", :selected => params[:user], label: "Employee" } %>
<% else %>
<%= builder.hidden_field :_destroy %>
<%= builder.link_to_remove "Remove" %>
<% end %>
<%= f.link_to_add "Add Team Member", :teams %>
<%= f.submit %>
<% end %>
projects controller:-
class ProjectsController < ApplicationController
before_action :set_project, only: [:show, :edit, :update, :destroy]
respond_to :html
def index
#projects = Project.all
respond_with(#projects)
end
def show
respond_with(#project)
end
def new
#project = Project.new
#project.pictures.build
#project.teams.build
respond_with(#project)
end
def edit
#project = Project.find(params[:id])
#project.pictures.build
#project.teams.build
end
def create
#project = Project.new(project_params)
if #project.save
flash[:notice] = "Successfully created project."
redirect_to #project
else
render :action => 'new'
end
end
def update
#project.update(project_params)
respond_with(#project)
end
def destroy
#project.destroy
respond_with(#project)
end
private
def set_project
#project = Project.find(params[:id])
end
def project_params
params.require(:project).permit(:id, :title, :description, :status, :phase, :location, :image, pictures_attributes: [:id, :image], teams_attributes: [:project_id, :user_id])
end
end

Resources