Problems with defining #shops variable NoMethodError - ruby-on-rails

I've created two user models called "user" and "shop". When I try to use the #shop variable as shop (like in shop.name) it will not work, but user.name will work. So I missed defining shop at some point, and cannot figure out where to fix it.
Here's the error I get:
NoMethodError (undefined method `name' for nil:NilClass):
app/views/shops/index.html.erb:7:in `block in _app_views_shops_index_html_erb__1785913569146145211_70081842378680'
app/views/shops/index.html.erb:5:in `_app_views_shops_index_html_erb__1785913569146145211_70081842378680'
This index page for user works:
user/index.html.erb
<% provide(:title, 'All users') %>
<h1>All users</h1>
<ul class="users">
<% #users.each do |user| %>
<li>
<%= link_to user.name, user %>
</li>
<% end %>
</ul>
But this one for shops does not b/c of shop.name:
shop/index.html.erb
<% provide(:title, 'All shops') %>
<h1>All shops</h1>
<ul class="shops">
<% #shops.each do |shop| %>
<li>
<%= link_to shop.name, shop %>
</li>
<% end %>
</ul>
Here is the shops controller: shops_controller.rb
class ShopsController < ApplicationController
#add before action for index
before_action :correct_shop, only: [:edit, :update]
def index
#shops = Shop.all
end
def show
#shop = Shop.find(params[:id])
end
def new
#shop = Shop.new
end
def create
#shop = Shop.new(shop_params)
if #shop.save
shop_log_in #shop
flash[:success] = "Thank you for signing up, welcome to AccessOBD!"
redirect_to shop_home_path
else
render 'new'
end
end
def edit
#shop = Shop.find(params[:id])
end
def update
#shop = Shop.find(params[:id])
if #shop.update_attributes(shop_params)
flash[:success] = "Profile updated"
redirect_to #shop
else
render 'edit'
end
end
private
def shop_params
params.require(:shop).permit(:name, :address, :city, :state, :zip, :email, :phone, :password,
:password_confirmation, :picture)
end
def correct_shop
#shop = Shop.find(params[:id])
redirect_to(root_url) unless current_shop?(#shop)
end
end
And here is the session helper for shops: ShopSessionsHelper.rb
module ShopSessionsHelper
# Logs in the given shop.
def shop_log_in(shop)
session[:shop_id] = shop.id
end
# Remembers a shop in a persistent session.
def shop_remember(shop)
shop.remember
cookies.permanent.signed[:shop_id] = shop.id
cookies.permanent[:remember_token] = shop.remember_token
end
def current_shop?(shop)
shop == current_shop
end
# Returns the shop corresponding to the remember token cookie.
def current_shop
if (shop_id = session[:shop_id])
#current_shop ||= Shop.find_by(id: shop_id)
elsif (shop_id = cookies.signed[:shop_id])
shop = Shop.find_by(id: shop_id)
if shop && shop.authenticated?(cookies[:remember_token])
shop_log_in shop
#current_shop = shop
end
end
end
# Returns true if the shop is logged in, false otherwise.
def shop_logged_in?
!current_shop.nil?
end
def shop_forget(shop)
shop.forget
cookies.delete(:shop_id)
cookies.delete(:remember_token)
end
# Logs out the current shop.
def shop_logout
shop_forget(current_shop)
session.delete(:shop_id)
#current_shop = nil
end
# Redirects to stored location (or to the default).
def shop_redirect_back_or(default)
redirect_to(shop)
session.delete(:forwarding_url)
end
# Stores the URL trying to be accessed.
def store_location
session[:forwarding_url] = request.url if request.get?
end
end
index.html.erb former
<% #shops.each do |shop| %>
<li>
<div class= "shop-name pull-left">
<%= link_to shop.name, shop %>
<% if current_shop.admin? && !current_shop?(shop) %>
| <%= link_to "(Delete Shop)", shop, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
</div>
<div class= "shop-address pull-right">
<p><%= shop.address %> <br> <%= shop.city %>, <%= shop.state %> <%= shop.zip %> <br> <%= shop.phone %></p>
</div>
</li>
<% end %>

Some of your records are nil, to identify them run the following code, you will get index values of those records
<% #shops.each_with_index do |shop, index| %>
<li>
<% unless shop.blank? %>
<%= link_to shop.name, shop %>
<% else %>
<%= "Record nil at " + index.to_s %>
<% end %>
</li>
<% end %>

Related

Getting user phone number and sending a message in ruby on rails

I am working on a messaging app in ruby and i am currently encountering a blocker which i can not fix. I have been using tutorials for this and i think part of the reason i cannot find the solution is because of that. My app allows the users to log in and sign up,they can then add,view and edit contact. Finally the can send a message to different recipients. The problem is, i cannot get the recipients in the contacts and send them a message. I am only able to select my name as a user(which is not what its intended to do). I have attached the controllers used here:
contacts_controller
class ContactsController < ApplicationController
def index
#contacts = Contact.all
end
def new
#contact = Contact.new
end
def create
#contact = Contact.new(contact_params)
if #contact.save
flash[:success]= "new contact successfully added!"
redirect_to contacts_path
else
render 'new'
end
end
def edit
#contact = Contact.find(params[:id])
end
def update
#contact = Contact.find(params[:id])
permitted_columns = params.require(:contact).permit(:name, :company, :email, :phone)
#contact.update_attributes(permitted_columns)
redirect_to contacts_path
end
def destroy
#contact = Contact.find(params[:id])
#contact.destroy
redirect_to contacts_path
end
private
def contact_params
params.require(:contact).permit(:name, :company, :email, :phone)
end
end
messages_controller
class MessagesController < ApplicationController
def index
#messages = Recipient.where(:user_id => current_user.id).order('created_at DESC')
end
def new
#message = Message.new
#recipients = Contact.all
end
def create
#message = current_user.messages.build(message_params)
if #message.save
flash[:success]= "Message sent!"
redirect_to contacts_path
else
flash[:alert]= "sorry!message unsent"
render :new
end
end
private
def message_params
params.require(:message).permit(:body, :sender_id, user_tokens:[])
end
end
users_controller
class UsersController < ApplicationController
def index
end
def create
user = User.new(user_params)
if user.save
session[:user_id] = user.id
redirect_to '/contact'
else
flash[:register_errors] = user.errors.full_messages
redirect_to '/'
end
end
private
def user_params
params.require(:user).permit(:fname, :lname, :email, :password, :password_confirmation)
end
end
sessions_controller
class SessionsController < ApplicationController
def create
user = User.find_by(email:login_params[:email])
if user && user.authenticate(login_params[:password])
session[:user_id] = user.id
redirect_to '/contact'
else
flash[:login_errors] = ['invalid username or password']
redirect_to '/'
end
end
def destroy
session[:user_id] = nil
redirect_to '/', notice: 'Successfully logged out!'
end
private
def login_params
params.require(:login).permit(:email,:password)
end
end
The _recipient.html.erb is rendered by the new.html.erb. Here is the code:
<div class="container vertical-center">
<div id ="stream">
<%= form_for :message, url:messages_path do |f| %>
<%= f.text_area :body, id: "url", placeholder: "Message", class: "message_body" %>
<div id="stream-list" class="follow-list">
<ul>
<% #recipients.each do |contact| %>
<label for="user<%=contact.id%>" >
<li id="stream_item">
<span class="list-group-item"><%= contact.name %></span><%= check_box_tag "message[user_tokens][]",user.id, #message.users.include?(user), id: "user#{user.id}" %>
</li>
</label>
<br>
<% end %>
</ul>
</div>
<div class="stream-footer">
<%= f.button :submit, class: "btn btn-success" %>
<% end %>
</div>
</div>
</div>
Here is the error when i try to write a message
It's not very clear why you use local variable user in your view template. I think it's just an error and contact variable is supposed to be used instead:
<span class="list-group-item"><%= contact.name %></span><%= check_box_tag "message[user_tokens][]", contact.id, #message.users.include?(contact), id: "user#{contact.id}" %>
Also, a small HTML error: ul tag should contain li tags; other tags are not allowed as direct descendants. So I would also rewrite that list as:
<ul>
<% #recipients.each do |contact| %>
<li id="stream_item">
<label for="user<%=contact.id%>" >
<span class="list-group-item"><%= contact.name %></span><%= check_box_tag "message[user_tokens][]", contact.id, #message.users.include?(contact), id: "user#{contact.id}" %>
</label>
</li>
<br>
<% end %>
</ul>

error "Couldn't find User without an ID" when trying to create a tweet

I'm trying to make a twitter clone where a tweet displays the username of the user next to it. however getting the above error message and highlighting the first line of my create method. any ideas on how to solve.
I've done the association already.
thanks
class TweetsController < ApplicationController
def index
#tweets = Tweet.all.order("created_at DESC")
#tweet = Tweet.new
end
def show
#tweet = Tweet.find(params[:id])
end
def new
# #tweet = Tweet.new
end
def create
#user = User.find(params[:id])
#tweet = Tweet.new(tweet_params)
#tweet.user = #user
if #tweet.save
redirect_to tweets_path
end
end
private
def tweet_params
params.require(:tweet).permit(:content, :user_id)
end
end
tweets
<%= simple_form_for #tweet, id: "form-submit" do |f| %>
<%= f.input :content %>
<%= f.button :submit, class: "btn btn-danger" %>
<% end %>
<% #tweets.each do |tweet| %>
<ul>
<li>
<%= tweet.content %>
<%= tweet.user.username %>
</li>
</ul>
<% end %>
Your form doesn't have id field, so params[:id] is nil.
params hash does not contain id, because of that you are getting this error.
Just modify your create action as
def create
#user = current_user
#tweet = Tweet.new(tweet_params)
#tweet.user = current_user
if #tweet.save
redirect_to tweets_path
end
end
Or
instead of above you can also pass an user_id from the form.
<%= simple_form_for #tweet, id: "form-submit" do |f| %>
<%= f.input :content %>
<%= f.hidden_field :user_id, value: current_user.try(:id) %>
<%= f.button :submit, class: "btn btn-danger" %>
<% end %>
then modify create action as
def create
#tweet = Tweet.new(tweet_params)
if #tweet.save
redirect_to tweets_path
end
end
NOTE: Assuming that you are using devise gem for authentication
You are defining tweet.users after using tweet_params, since for tweet_params the user is not defined, that's why you are getting this error.
By answer accepted here, most appropriate change could be:
def new
#tweet = current_user.tweets.new
end
def create
#tweet = Tweet.new(tweet_params)
if #tweet.save
redirect_to tweets_path
end
end
nothing else was needed to be done.

Rails: link_to delete from different controller

Right now I have a like button that allows you to like foods. When you try to unlike the food, I get this error:
The action 'destroy' could not be found for UsersController
I'm not sure why it is looking for the destroy action in the users controller. My only guess is because the button is on the user show page, so I assume it defaults to that controller, but how would I access the delete method from my votes controller?
Shared like form
<% unless current_user.votes.empty? || current_user.votes.pluck(:food_id).include?(food.id) %>
<%= form_for #vote do |f| %>
<%= f.hidden_field 'food_id', food.id %>
<%= f.hidden_field 'user_id', food.user.id %>
<%= f.submit "Vote", :class => "like_button" %>
<% end %>
<% else %>
<% vote = food.votes.where(user_id: current_user.id).first %>
<div class="unlike_button">
<%= button_to "Unlike", vote, method: :delete %>
</div>
<% end %>
class VotesController < ApplicationController
def index
#votes = Vote.all
end
def new
#vote = Vote.new
end
def create
#vote = Vote.new(vote_params)
if #vote.save
puts #vote
flash[:notice] = "Thanks for voting!"
redirect_back(fallback_location: root_path)
else
puts "No"
flash[:notice] = "Something went wrong"
redirect_back(fallback_location: root_path)
end
end
def destroy
#vote = Vote.find(params[:id])
if #vote.destroy!
flash[:notice] = "Unvoted!"
redirect_back(fallback_location: root_path)
end
end
private
def vote_params
params.require(:vote).permit(:food_id, :user_id)
end
end
class Vote < ApplicationRecord
belongs_to :user
belongs_to :food
end

Iterate through an array to create rails objects

I am having trouble finding any information on how to iterate through an array and create objects.
My form creates a selectable list of users that when checked, pass the user_ids as an array object.
invitations\new.html.rb
<%= bootstrap_form_for Invitation.new do |f| %>
<br>
<ul>
<%= f.hidden_field :attended_event_id, :value => #event_selected.id %>
<li>
<%= check_box_tag 'attendee_id[]', user.id %>
<%= h user.name %>
</li>
<% end %>
</ul>
<br>
<%= f.submit "Invite Selected Users" %>
<% end %>
I would like to then create new Invitations objects by combining the attended_event_id with all of the objects in the attendee_id array.
After a bit of trouble I got the basics of my controller working but only by passing in the user_id as a text entry. Below is my Invitations controller. Not really sure where to start on this one as I haven't been able to find a good example.
invitations_controller.rb
def create
#invitation = Invitation.new(invite_params)
if #invitation.save!
flash.now[:success] = "Invited!"
redirect_to root_path
else
flash.now[:error] = "Failure!"
redirect_to root_path
end
end
private
def invite_params
params.require(:invitation).permit(:attended_event_id, :attendee_id)
end
end
Do you mean something like this?
<%= bootstrap_form_for Invitation.new do |f| %>
<br>
<ul>
<%= f.hidden_field :attended_event_id, :value => #event_selected.id %>
<% users.each do |user| %>
<li>
<%= check_box_tag 'invitation[attendee_id][]', user.id %>
<%= h user.name %>
</li>
<% end %>
</ul>
<br>
<%= f.submit "Invite Selected Users" %>
<% end %>
def create
#invitations = invite_params[:attendee_id].map do |attendee_id|
Invitation.new(
attended_event_id: invite_params[:attended_event_id],
attendee_id: attendee_id
)
end
if #invitations.any?(&:invalid?)
flash.now[:error] = "Failure!"
redirect_to root_path
else
#invitations.each(&:save!)
flash.now[:success] = "Invited!"
redirect_to root_path
end
end
private
def invite_params
params.require(:invitation).permit(:attended_event_id, {:attendee_id => []})
end
There is a good basic example on RailsGuides
http://guides.rubyonrails.org/form_helpers.html#binding-a-form-to-an-object
Do you want to achieve something like this:
def create
params[:attendee_id].each do |user_id|
Invitation.create(:attended_event_id => params[:attended_event_id], :attendee_id => user_id)
end
.
.
.
end

Ruby on Rails app - Adding multiple dynamic input field

I'm a Rails newbie, and I have a RoR app that I'm working on, the app is supposed to allow invited guests to RSVP to a wedding.
I have allowed for fields to be dynamically added, in order to include additional guests (family of an invited guest). But when I add the dynamic field and add the names, only the last name is displayed in the index.
Is there anything specific I need to do to render all other names together in a field within the table?
This is my current controller thus far:
class GuestsController < ApplicationController
skip_before_filter :authenticate_user!, only: [:new, :create]
def index
#guests = Guest.all
end
def new
#guest = Guest.new
end
def create
#guest = Guest.all
#guest = Guest.create(guest_params)
if #guest.save
respond_to do |format|
format.html { redirect_to :back, notice: 'Thank you for replying' }
format.js
end
else
respond_to do |format|
format.html { render 'new' }
format.js
end
end
end
def destroy
#guest = Guest.find(params[:id])
#guest.destroy
redirect_to guests_path
end
private
def guest_params
params.require(:guest).permit(:status, :name, :message)
end
end
Place Guest in place of User
users controler
def new
#users = []
5.times do
#users << User.new
end
end
if params.has_key?("user")
User.create(users_params(params["user"]))
else
params["users"].each do |user|
if user["name"] != nil || user["age"] != nil
User.create(users_params(user))
end
end
end
def users_params(my_params)
my_params.permit(:name, :age)
end
users_form
<%= form_tag users_path do %>
<% #users.each do |user| %>
<%= fields_for 'users[]', user do |u| %>
<div class="field">
<%= u.label :name %><br>
<%= u.text_field :name %>
</div>
<div class="field">
<%= u.label :age %><br>
<%= u.number_field :age %>
</div>
<% end %>
<% end %>
<div class="actions">
<%= submit_tag %>
</div>
<% end %>

Resources