undefined method `company' for nil:NilClass - javascript

I keep receving an error on my home page saying
'undefined method `company' for nil:NilClass'
for the first line of the following code displayed below. I am not really sure on how to fix this. I have two Controllers for both companies and customers because I am creating a two-sided marketplace.
When the user clicks the logo at the top instead of being redirected to the welcome page, the login page is being rendered since the home page is the root_path but I am using devise for before_action authenticate is being used.
<% if((current_user.company) || (current_user.customer)) %>
<%= render 'pages/welcome' %>
<% else %>
<% if current_user.is_company %>
<%= render 'companies/form', company: #company%>
<% else %>
Here is the home.html.erb file with the code which is the root_path
<% if((current_user.company) || (current_user.customer)) %>
<%= render 'pages/welcome' %>
<% else %>
<% if current_user.is_company %>
<%= render 'companies/form', company: #company%>
<% else %>
<%= render 'customers/form', customer: #customer%>
<% end %>
<% end %>
Here is my companiesController
class CompaniesController < ApplicationController
before_action :set_company, only: [:show, :edit, :update, :destroy]
def index
#companies = Company.all
end
# GET /companies/1
# GET /companies/1.json
def show
#company = Company.find(params[:company_id])
end
# GET /companies/new
def new
#company = Company.new
end
# GET /companies/1/edit
def edit
end
# POST /companies
# POST /companies.json
def create
#company = Company.new(company_params)
respond_to do |format|
if #company.save
format.html { redirect_to #company, notice: 'Company was successfully created.' }
format.json { render :show, status: :created, location: #company }
else
format.html { render :new }
format.json { render json: #company.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /companies/1
# PATCH/PUT /companies/1.json
def update
respond_to do |format|
if #company.update(company_params)
format.html { redirect_to #company, notice: 'Company was successfully updated.' }
format.json { render :show, status: :ok, location: #company }
else
format.html { render :edit }
format.json { render json: #company.errors, status: :unprocessable_entity }
end
end
end
# DELETE /companies/1
# DELETE /companies/1.json
def destroy
#company.destroy
respond_to do |format|
format.html { redirect_to companies_url, notice: 'Company was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_company
#company = Company.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the
white list through.
def company_params
params.require(:company).permit(:username, :phone, :website, :street, :city, :state, :country, :user_id)
end
end

it just says that the current_user is nil, you need to make sure that the user is logged in to use current_user.company

The log is giving you details as to why the company is returning a nil. The company requires an object in it for the page to load properly. But that is not so because no user is logged in for the company to have an object to return.
<% if((current_user.company) || (current_user.customer)) %> <%=
render 'pages/welcome' %> <% else %>
<% if current_user.is_company %> <%= render 'companies/form',
company: #company%> <% else %>
is returning a nil because no user is logged in.
You can first check if there is a user logged in and then render
something before this to prevent the error page
<% if(current_user) <% if((current_user.company) ||
(current_user.customer)) %>
<%= render 'pages/welcome' %> <% else %>
<% if current_user.is_company %>
<%= render 'companies/form', company: #company%> <% end %> <% else %> render something here <% end %>
Or simply log in to make sure this does not return a nil. But the first fix is the most ideal.

Related

Rails Realtime Chat: Is it secure to implement it with just plain javascript?

I've added a realtime chat to my rails application using only vanilla javascript. I've included it below. I'm just wondering, are there any security issues just looking at the code I've provided? I'm just not sure whether there's any issues with AJAX injections or any unknown unknowns I need to worry about. I didn't add ActionCable mainly because I don't need all of its functionality. Thanks for your help! :)
A chat has many private messages between 2 users. Users have many messages. I've added policies using pundit so only authorized users can access chats. And I'm using devise so only logged in users can access chats. Every model uses UUID.
chats/show.html.erb
<% if #messages %>
<div id="messages">
<%= render #messages %>
</div>
<% end %>
<%= form_with(model: [#chat, Message.new], local: false, html: { id: "message-form" }) do |form| %>
<div class="field">
<%= form.text_area :content, placeholder: "Send a message" %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
messages/_message.html.erb
<%= message.user.name %>
<%= message.content %>
messages/create.js.erb
var messages = document.querySelector("#messages");
messages.insertAdjacentHTML("beforeend", "<%= j render(#message) %>");
document.getElementById("message-form").reset();
controllers/messages_controller.rb
def create
#chat = Chat.find(params[:chat_id])
#message = #chat.messages.build(message_params)
#message.user = current_user
authorize #message
respond_to do |format|
if #message.save
format.html { redirect_to #chat, notice: 'Message was successfully created.' }
format.js
format.json { render :show, status: :created, location: #chat }
else
format.html { redirect_to #chat, alert: 'Message not created.' }
format.json { render json: #message.errors, status: :unprocessable_entity }
end
end
end
controllers/chats_controller.rb
def show
#listing = Listing.find(params[:listing_id])
#chats = #listing.chats
#chat = Chat.find(params[:id])
if #chat.messages
#messages = #chat.messages
end
end

I am trying to add comments withour refresh a page

When I try to add a comment, it doesnt append on table. When i refresh a page then it append. I dont know what is problem. I think I did everything well. There is no errors on page. And it goes in table whatever I add to table, but only after refresh a page.
show.html.erb
...
<table id="comments">
<tbody>
<% #article.comments.each do |comment| %>
<%= render 'comments/comment', comment: comment %>
<% end %>
</tbody>
...
_comment.html.erb
<tr>
<td><p><%= comment.name %></p></td>
<td><p><%= comment.body %></p></td>
<td><p><%= time_ago_in_words(comment.created_at) %> Ago</p></td>
<% if User.find_by(email: comment.name) == current_user %>
<td><%= link_to 'Delete', [comment.article, comment], method: :delete, data: { confirm: 'Are you sure?' } %></td>
<% else %>
<td> </td>
<% end %>
</tr>
create.js.erb
$('table#comments tbody').append("<%= j render #comment %>")
terminal
ActionController::UnknownFormat (ActionController::UnknownFormat):
app/controllers/comments_controller.rb:7:in `create'
routes.rb
Rails.application.routes.draw do
get 'search/index'
devise_for :users
get 'welcome/index'
get '/search', to: 'search#search'
resources :user
resources :articles do
resources :comments
member do
put "like" => "articles#like"
put "unlike" => "articles#unlike"
end
end
resources :search, only: [:index]
root 'welcome#index'
end
comments_controller.rb
def create
#article = Article.find(params[:article_id])
#comment = #article.comments.create(params[:comment].permit(:name, :body))
#comment.name = current_user.email
respond_to do |format|
if #comment.save
format.js
format.html { redirect_to #comment }
format.json { render :show, status: :created, location: #comment }
else
end
end
end
Because by default, format return from controller is html. So you need to add another formant js in controller to make js.erb work.
Your controller should be something like this:
def create
............
if #comment.save
respond_to do |format|
format.js
end
end
end
to handle the errors: in create.js.erb file, check #comment.errors.any? - then do whatever you want to do.

Update nested form attribute with a iteration

I'm currently trying to use the nested form with cocoon, is awesome !! But I'm facing to an interrogation and I don't know which way I should take.
Relations :
Ranch have Cows
Ranch have Productions
Production have nested form Iproductions
What I'm trying to do now is implement my iteration |c| into each of my iproductions:cow_id elements
My code:
(My_form production)=
<%- #cows.each do |c| %>
<div class="row">
<div class="col-md-12">
<div id="Order">
<%= f.simple_fields_for :iproductions do |ip| %>
<%= render 'iproductions_fields', f: ip, cow: c %>
<%end%>
<div class="Order_links">
<%= link_to_add_association c.name, f, :iproductions, cow: c, class: "btn btn-default" %>
</div>
</div>
</div>
</div>
(My iproductions_fields)=
<div class="form-inline clearfix">
<div class="nested-fields">
<%= f.input :cow_id, :input_html => { :cow_id => :cow } %>
<%= f.input :quantity, input_html: {class: "form-input form-control"} %>
<%= link_to_remove_association "Supprimer", f, class: "form-button btn btn-default" %>
</div>
</div>
(My productions_controllers)=
class ProductionsController < ApplicationController
before_action :authenticate_user!
skip_before_action :configure_sign_up_params
before_action :set_ranch
before_action :set_production, except: [:create, :new, :show]
before_action :set_production2, only: [:show]
# GET /productions
# GET /productions.json
def index
#productions = Production.all
end
# GET /productions/1
# GET /productions/1.json
def show
#iproductions = Iproduction.where(id: params[:production_id])
end
# GET /productions/new
def new
#production = #ranch.productions.build
#cows = #ranch.cows
end
# GET /productions/1/edit
def edit
#cows = #ranch.cows
end
# POST /productions
# POST /productions.json
def create
#production = #ranch.productions.create(production_params)
#production.update(date: Date.today)
#cows = #ranch.cows
respond_to do |format|
if #production.save
format.html { redirect_to ranch_production_path(#production.ranch_id, #production), notice: 'Production was successfully created.' }
format.json { render :show, status: :created, location: #production }
else
format.html { render :new }
format.json { render json: #production.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /productions/1
# PATCH/PUT /productions/1.json
def update
respond_to do |format|
if #production.update(production_params)
format.html { redirect_to ranch_production_path(#production.ranch_id, #production), notice: 'Production was successfully updated.' }
format.json { render :show, status: :ok, location: #production }
else
format.html { render :edit }
format.json { render json: #production.errors, status: :unprocessable_entity }
end
end
end
# DELETE /productions/1
# DELETE /productions/1.json
def destroy
#production.destroy
respond_to do |format|
format.html { redirect_to ranch_productions_path(#production.ranch_id), notice: 'Production was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_ranch
#ranch = Ranch.find(params[:ranch_id])
end
def set_production2
#production = Production.find_by(id: params[:id])
end
def set_production
#production = #ranch.productions.find_by(id: params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def production_params
params.require(:production).permit(:name, :ranch_id, :created_at, :date, iproductions_attributes: [:id, :date, :cow_id, :quantity, :_destroy])
end
end
My real view , so I would like to Assign each iproduction with the button which generate the iproductions_fields
So if you have any idea of which way I can try to achieve this goal, you're welcome,
Thanks in advance

Rails 5, Cocoon Gem - nested form inside nested form

I am trying to use cocoon gem to build nested forms.
I have models for Organisation, Package::Bip and Tenor.
The associations are:
Organisation
has_many :bips, as: :ipable, class_name: Package::Bip
accepts_nested_attributes_for :bips, reject_if: :all_blank, allow_destroy: true
Package::Bip (polymorphic)
belongs_to :ipable, :polymorphic => true, optional: true, inverse_of: :bip
has_one :tenor, as: :tenor
accepts_nested_attributes_for :tenor, reject_if: :all_blank, allow_destroy: true
Tenor (polymorphic)
belongs_to :tenorable, :polymorphic => true, optional: true
The forms have:
In my organisations/_form.html.erb, I have:
<%= f.simple_fields_for :bips do |f| %>
<%= f.error_notification %>
<%= render 'package/bips/bip_fields', f: f %>
<% end %>
<%= link_to_add_association 'Add another intellectual property resource', f, :bips, partial: 'package/bips/bip_fields' %>
In my bip_fields.html.erb nested form, I have:
<%# if #package_bips.tenor.blank? %>
<%= link_to_add_association 'Add timing', f, :tenor, partial: 'tenors/tenor_fields' %>
<%# end %>
<%= f.simple_fields_for :tenor do |tenor_form| %>
<%= f.error_notification %>
<%= render 'tenors/tenor_fields', f: tenor_form %>
<% end %>
Javascript
The cocoon docs suggest adding a js file to specify association-insertion-node as a function. In my tenor_subform.js I have:
$(document).ready(function() {
$(".add_tenor a").
data("association-insertion-method", 'append').
data("association-insertion-node", function(link){
return link.closest('.row').next('.row').find('.tenor_form')
});
});
Controllers
In my organisation controller, I have:
def new
#organisation = Organisation.new
#organisation.bips
end
Note: I'm not sure if I need to add another line to my new action to create the organisation.bip.tenor instance. I'm also unsure if im supposed to add has_one through association on the organisation.rb that references the tenor.
def organisation_params
params.fetch(:organisation, {}).permit(:title, :comment,
bips_attributes: [:id, :status, :_destroy,
tenor_attributes: [:id,:commencement, :expiry, :_destroy]
],
In my tenor controller, I have:
def tenor_params
params.require(:tenor).permit( :commencement, :expiry)
end
ERRORS
I am not sure if I need to add tenor actions to the organisation controller (the ultimate parent of bip which in turn is the parent of tenor).
When I save all of this and try it, I get an error that says:
unknown attribute 'tenor_id' for Tenor.
When I see other SO posts with this error, its often because the :id attribute hasn't been whitelisted in the parent class. I have done that.
Can anyone see what I've done wrong?
Tenor controller
class TenorsController < ApplicationController
before_action :set_tenor, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
# after_action :verify_authorized
def index
#tenors = Tenor.all
# authorize #tenors
end
def show
end
def new
#tenor = Tenor.new
# authorize #tenor
end
def edit
end
def create
#tenor = Tenor.new(tenor_params)
# authorize #tenor
respond_to do |format|
if #tenor.save
format.html { redirect_to #tenor }
format.json { render :show, status: :created, location: #tenor }
else
format.html { render :new }
format.json { render json: #tenor.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #tenor.update(tenor_params)
format.html { redirect_to #tenor }
format.json { render :show, status: :ok, location: #tenor }
else
format.html { render :edit }
format.json { render json: #tenor.errors, status: :unprocessable_entity }
end
end
end
def destroy
#tenor.destroy
respond_to do |format|
format.html { redirect_to action: :index }
format.json { head :no_content }
end
end
private
def set_tenor
#tenor = Tenor.find(params[:id])
# authorize #tenor
end
def tenor_params
params.require(:tenor).permit(:express_interest, :commencement, :expiry, :enduring, :repeat, :frequency)
end
end
You has_one relation is wrongly declared. Because you say as: :tenor makes it look for a tenor_id.
You have to declare it as follows:
has_one :tenor, as: :tenorable
Your model does not see the id of nested_attr.Add :inverse_of => #{model}.
Example:
class Tenor < ActiveRecord::Base
has_many :traps, :inverse_of => :bips
end
For more information look this or this documentation.

Rails ajax append single item from collection

In my app I have a commenting system in place that displays comments as a collection and I've got ajax commenting working but currently it renders the entire collection again but what I want is to just append the latest comment. Here's my code:
comments_controller.rb
class CommentsController < ApplicationController
before_filter :authenticate_member!
before_filter :load_commentable
before_filter :find_member
def index
redirect_to root_path
end
def new
#comment = #commentable.comments.new
end
def create
#comment = #commentable.comments.new(params[:comment])
#comment.member = current_member
respond_to do |format|
if #comment.save
format.html { redirect_to :back }
format.json
format.js
else
format.html { redirect_to :back }
format.json
format.js
end
end
end
def destroy
#comment = Comment.find(params[:id])
respond_to do |format|
if #comment.member == current_member || #commentable.member == current_member
#comment.destroy
format.html { redirect_to :back }
else
format.html { redirect_to :back, alert: 'You can\'t delete this comment.' }
end
end
end
private
def load_commentable
klass = [Status, Medium, Project, Event, Listing].detect { |c| params["#{c.name.underscore}_id"] }
#commentable = klass.find(params["#{klass.name.underscore}_id"])
end
def find_member
#member = Member.find_by_user_name(params[:user_name])
end
end
statuses_controller
def show
#status = Status.find(params[:id])
#commentable = #status
#comments = #commentable.comments.order('created_at desc').page(params[:page]).per_page(15)
#comment = Comment.new
respond_to do |format|
format.html # show.html.erb
format.json { redirect_to profile_path(current_member) }
format.js
end
end
statuses/show.html.erb
<% if member_signed_in? %>
<div id="comm_form_wrap">
<%= render "shared/comment_form" %>
</div>
<div id="comments_<%= #commentable.id %>">
<%= render partial: "shared/comments", :collection => #comments, :as => :comment %>
</div>
<% end %>
shared/_comments.html.erb
<div id="comment_<%= comment.commentable.id %>_<%= comment.id %>" class="comments">
<span class="comment_av">
<%= comment_avatar_link_2 comment.member, :class => "com_av", title: comment.member.full_name, alt: comment.member.full_name %>
</span>
<span>
<div class="comment_name">
<% if comment.member == #commentable.member %>
<%= link_to comment.member.user_name, profile_path(comment.member) %> <span class="owner">Creator</span>
<% else %>
<%= link_to comment.member.user_name, profile_path(comment.member) %>
<% end %>
<% if comment.member == current_member || #commentable.member == current_member %>
<span class="comment_del">
<%= link_to image_tag("Delete.png", title: 'Delete'), [#commentable, comment], remote: true, method: :delete, data: { confirm: 'Are you sure?' } %>
</span>
<% end %>
<span class="meta">
<%= time_ago_in_words(comment.created_at) %>
</span>
</div>
<div class="com_con">
<%= Rinku.auto_link(comment.content).html_safe %>
</div>
</span>
</div>
comments/create.js.erb
$("#comments_<%= #commentable.id %>").html("<%= escape_javascript(render :partial => 'shared/comments', :collection => #comments, :as => :comment) %>");
$('#comment_form')[0].reset();
If I just change html to append in the create.js.erb file it will append the entire collection of comments. I guess I could copy and paste the code from my comments partial but that'd be a lot of code and I wouldn't know how to define the variables that way. What's the best way for me to append the single new comment? Thanks in advance.
I was able to figure this one out. Instead of rendering or appending the collection I could just append #comment like so:
$("#comments_<%= #commentable.id %>").append("<%= escape_javascript(render :partial => #comment, :locals => {:comment => #comment}) %>");
Then I just needed to create a _comment.html.erb partial in my comments folder.

Categories