RoR : You have a nil object you did not expect - ruby-on-rails

Been Facing this issue,I Have as my view
<%= form_for(:pin, :url => {:action =>"fees"}) do |f| %>
<%= f.text_field :pin_no %>
<%= f.submit "Check Pin" , :class => "new_button round" %>
<% end %>
and in my controller i have
def fees
#title = "Pay Fees"
pin = Pin.check_pin(params[:pin][:pin_no])
if pin.nil?
flash.now[:error] = "Pin is not Avaliable"
render 'fees'
else
flash.now[:success] = "Pin Avaliable"
end
end
in my model, i have a check_pin method defined thus
def check_pin(pin_to_check)
pin = find_by_pin_no(pin_to_check)
if pin.nil?
nil
else
pin
end
end
and i always have this error
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]
what am i missing here please?

You get params[:pin][:pin_no] only when you post the form so it is giving error nil.[] so add request.post? to check it only when form is post
def fees
#title = "Pay Fees"
if request.post?
pin = Pin.check_pin(params[:pin][:pin_no])
if pin.nil?
flash.now[:error] = "Pin is not Avaliable"
render 'fees'
else
flash.now[:success] = "Pin Avaliable"
end
end
end

What if you try to simplify it a bit and scrap the check pin method and just do this:
def fees
#title = "Pay Fees"
if p = Pin.find_by_pin_no params[:pin][:pin_no]
flash.now[:success] = "Pin: #{p} is Avaliable"
else
flash.now[:error] = "Pin is not Avaliable"
render 'fees'
end
end

Related

Rails: How not to save value with using time_select

I'm trying to add time_select with include_blank. I'm doing this:
<%= f.time_select :start_at, include_blank: true, ampm: true %><br>
What I'd like to do is to delete value (save nil?) if blank is selected in view.
Although I tried the following posts, it didn't work for me.
time_select blank field saves a default time when form is submitted
Optional time_select with allow_blank defaults to 00:00
1) When I try as below, no error is appeared, but 00:00:00 is saved.
controller
def update
#event = Event.find(params[:id])
if event_params["start_at(4i)"].blank? or event_params["start_at(5i)"].blank?
#event.start_at = nil
end
if #event.update(event_params)
flash[:success] = "event updated!"
redirect_to root_url
else
render 'edit'
end
end
2) When I try as below (change if clause), no error is appeared, but 00:00:00 is saved.
controller
def update
#event = Event.find(params[:id])
if params[:id]["start_at(4i)"].blank? or params[:id]["start_at(5i)"].blank?
#event.start_at = nil
end
if #event.update(event_params)
flash[:success] = "event updated!"
redirect_to root_url
else
render 'edit'
end
end
3) When I try as below (add before_action), no error is appeared, but 00:00:00 is saved.
controller
before_action :blank_time, only: [:update]
def update
#event = Event.find(params[:id])
if #event.update(event_params)
flash[:success] = "event updated!"
redirect_to root_url
else
render 'edit'
end
end
private
def blank_time
if params[:id]["start_at(4i)"].blank? or params[:id]["start_at(5i)"].blank?
params[:id]['start_at(1i)'] = ""
params[:id]["start_at(2i)"] = ""
params[:id]["start_at(3i)"] = ""
params[:id]["start_at(4i)"] = ""
params[:id]["start_at(5i)"] = ""
end
end
4) When I try as below (use nil instead of ""), error is appeared.
error
IndexError (string not matched):
app/controllers/events_controller.rb:106:in `[]='
app/controllers/events_controller.rb:106:in `blank_time'
controller
before_action :blank_time, only: [:update]
def update
#event = Event.find(params[:id])
if #event.update(event_params)
flash[:success] = "event updated!"
redirect_to root_url
else
render 'edit'
end
end
private
def blank_time
if params[:id]["start_at(4i)"].blank? or params[:id]["start_at(5i)"].blank?
params[:id]['start_at(1i)'] = nil
params[:id]["start_at(2i)"] = nil
params[:id]["start_at(3i)"] = nil
params[:id]["start_at(4i)"] = nil
params[:id]["start_at(5i)"] = nil
end
end
It would be appreciated if you could give me any advice.
UPDATE
Although I change the edit in events_controller.rb as below, the error ActiveModel::MissingAttributeError (can't write unknown attribute 'start_at(4i)'): is displayed.
def edit
#room = Room.find(params[:room_id])
#event = #room.events.find(params[:id])
#event['start_at(4i)'] = #event.start_at.split(':')[0] #the error occur here
#event['start_at(5i)'] = #event.start_at.split(':')[1]
end
My idea works like this:
Migration:
class CreateTests < ActiveRecord::Migration[5.0]
def change
create_table :tests do |t|
t.string :time
t.timestamps
end
end
end
Form:
<%= form_for(test) do |f| %>
<% if test.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(test.errors.count, "error") %> prohibited this test from being saved:</h2>
<ul>
<% test.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :time %>
<%= f.time_select :time, include_blank: true, ampm: false %><br>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Controller:
This will save : when value send are null where you can use conditional to check if parameters are null or and set value of time. //It's consuming much time and I skipped for you to complete.
def create
#test = Test.new(test_params)
#time = (params[:test]['time(4i)']).to_s
#time_ampm = (params[:test]['time(5i)']).to_s
#test.time = #time+":"+ #time_ampm
respond_to do |format|
if #test.save
format.html { redirect_to #test, notice: 'Test was successfully created.' }
format.json { render :show, status: :created, location: #test }
else
format.html { render :new }
format.json { render json: #test.errors, status: :unprocessable_entity }
end
end
end
For updating
def edit
#test = Test.find(params[:id])
#test['time(4i)'] = #test.time.split(':')[0]
#test['time(5i)'] = #test.time.split(':')[1]
end
def update
#test = Test.find(params[:id])
#time = (params[:test]['time(4i)']).to_s
#time_ampm = (params[:test]['time(5i)']).to_s
#test.time = #time+":"+ #time_ampm
#test.update(test_params)
end
Assigning #event.starts_at to nil does nothing as the attributes in #event_params is used when calling #update, overwriting your initial assignment.
Overwriting the starts_at attribute in your params should work instead.
def update
#event = Event.find(params[:id])
if event_params["start_at(4i)"].blank? or event_params["start_at(5i)"].blank?
event_params = event_params.reject { |k, v| k.starts_with? 'starts_at' }
.merge(starts_at: nil)
end
if #event.update(event_params)
flash[:success] = "event updated!"
redirect_to root_url
else
render 'edit'
end
end
The following line finds and remove the parameters for starts_at(1i) to starts_at(5i), then sets the whole starts_at attribute to be nil:
event_params.reject { |k, v| k.starts_with? 'starts_at' }.merge(starts_at: nil)

Ruby: If last variable was saved more than 3 hours ago

I have a ruby form to submit reports for an exercise on my app. An exercise has_many reports. I want to create an if statement that makes this form only appear if the last report from that exercise was saved more than 3 hours ago.
So far I have:
But this is creating a NoMethodError saying undefined method 'report' for #<Exercise:0x007f9c892f48b0>.
It's being displayed on my workouts#show page (a workout has_many exercises, in case it helps), so I believe this is the reigning controller:
class WorkoutsController < ApplicationController
def index
#workouts = Workout.all
end
def show
#workout = Workout.find(params[:id])
#exercise = Exercise.new
#report = Report.new
end
def new
#workout = Workout.new
#workout.user_id = current_user
end
def create
#workout = Workout.new(workout_params)
#workout.user = current_user
if #workout.save
flash[:notice] = "Workout was saved successfully."
redirect_to #workout
else
flash.now[:alert] = "Error creating workout. Please try again."
render :new
end
end
def edit
#workout = Workout.find(params[:id])
end
def update
#workout = Workout.find(params[:id])
#workout.name = params[:workout][:name]
#workout.workout_type = params[:workout][:workout_type]
#workout.teaser = params[:workout][:teaser]
#workout.description = params[:workout][:description]
#workout.video = params[:workout][:video]
#workout.difficulty = params[:workout][:difficulty]
#workout.trainer = params[:workout][:trainer]
#workout.user_id = params[:workout][:user_id]
if #workout.save
flash[:notice] = "Workout was updated successfully."
redirect_to #workout
else
flash.now[:alert] = "Error saving workout. Please try again."
render :edit
end
end
def destroy
#workout = Workout.find(params[:id])
if #workout.destroy
flash[:notice] = "\"#{#workout.name}\" was deleted successfully."
redirect_to action: :index
else
flash.now[:alert] = "There was an error deleting the workout."
render :show
end
end
private
def workout_params
params.require(:workout).permit(:name, :workout_type, :teaser, :description, :video, :difficulty, :trainer, :user_id)
end
end
Any ideas where I'm going wrong?
ADDITIONAL INFORMATION:
This bit is technically on my workouts#show page:
<% if #workout.exercises.count == 0 %>
<p>Looks like you get a freebie for this one! No score report today. Rest up and drink some water. It ain't always that easy...</p>
<% else %>
<% #workout.exercises.each do |exercise| %>
<%= render 'reports/form', report: #report, exercise: exercise %>
<% if current_user.admin? %>
<div class="text-center"><%= link_to "Delete #{exercise.name}", [exercise], method: :delete, data: { confirm: 'Are you sure?' } %></div>
<% end %>
<hr>
<% end %>
But here is the partial it renders, where the code in question actually lies:
<% if exercise.report.last != nil && exercise.report.last.created_at < ( DateTime.now - (3/24.0)) %>
<%= form_for report,
:url => { :controller => "reports",
:action => :create,
:exercise_id => exercise.id } do |f| %>
<div class="row">
...
It seems you calling singularized report instead of reports.
if exercise.report.last
If reports relates to exercise as has_many you need to call it with exercise.reports.last
Also, you mentioned results in your question, but calling reports in your view.
An exercise has_many results.
...
exercise.report.last
Please be sure you calling appropriate pluralize method reports or results

undefined method `picture' for nil:NilClass using carrierwave

I am making a form in my rails application where people have the option of adding images and I am using 'carrierwave' but I am getting an undefined method error on the edit page. Here is the code for the form:
<%= title "Add Item to #{#todo_list.title}" %>
<%= form_for [#todo_list, #todo_item], builder: FoundationFormBuilder do |form| %>
<%= render partial: 'form', locals: { form: form } %>
<%= form.file_field :picture %>
<% end %>
Here I can see the upload button and it is working fine but on the edit page I get the above stated error. Code for my edit page:
<%= title "Editing Todo Item" %>
<%= form_for [#todo_list, #todo_item], builder: FoundationFormBuilder do |form| %>
<%= render partial: 'form', locals: { form: form } %>
<% end %>
<div class="row">
<div class="small-12 columns">
<%= link_to "Delete", todo_list_todo_item_path(#todo_list, #todo_item), method: :delete, data: { confirm: "Are you sure?" }, class: "button radius expand alert" %>
</div>
<%= #todo_item.picture %>
</div>
Why is this showing an undefined method error. I tried creating a method in my todo_item model but its still showing the above error.
Controller for todo_item:
class TodoItemsController < ApplicationController
before_action :require_user
before_action :find_todo_list
before_action :set_back_link, except: [:index]
def index
go_back_link_to todo_lists_path
end
def new
#todo_item = #todo_list.todo_items.new
end
def create
#todo_item = #todo_list.todo_items.new(todo_item_params)
if #todo_item.save
flash[:success] = "Added todo list item."
redirect_to todo_list_todo_items_path
else
flash[:error] = "There was a problem adding that todo list item."
render action: :new
end
end
def edit
#todo_item = #todo_list.todo_items.find(params[:id])
end
def update
#todo_item = #todo_list.todo_items.find(params[:id])
if #todo_item.update_attributes(todo_item_params)
flash[:success] = "Saved todo list item."
redirect_to todo_list_todo_items_path
else
flash[:error] = "That todo item could not be saved."
render action: :edit
end
end
def destroy
#todo_item = #todo_list.todo_items.find(params[:id])
if #todo_item.destroy
flash[:success] = "Todo list item was deleted."
else
flash[:error] = "Todo list item could not be deleted."
end
redirect_to todo_list_todo_items_path
end
def complete
#todo_item = #todo_list.todo_items.find(params[:id])
#todo_item.toggle_completion!
redirect_to todo_list_todo_items_path, notice: "Todo item updated."
end
def url_options
{ todo_list_id: params[:todo_list_id] }.merge(super)
end
private
def set_back_link
go_back_link_to todo_list_todo_items_path(#todo_list)
end
def find_todo_list
#todo_list = current_user.todo_lists.find(params[:todo_list_id])
end
def todo_item_params
params[:todo_item].permit(:content)
end
end
To display your image you should change
<%= #todo_item.picture %>
to
<%= image_tag(#todo_item.picture_url) %>

undefined method `accepted_user_friendships'

NoMethodError in UserFriendshipsController#index
undefined method `accepted_user_friendships'
I'm getting the above error message when clicking on the 'accepted' link within my index.html page. All the other links function properly except this one. Thanks in advance. Any help is greatly appreciated.
user_friendships_controller
class UserFriendshipsController < ApplicationController
before_filter :authenticate_user!
respond_to :html, :json
def index
#user_Friendships = UserFriendshipDecorator.decorate_collection(friendship_association.all)
respond_with #user_Friendships
end
def accept
#user_friendship = current_user.user_friendships.find(params[:id])
if #user_friendship.accept_mutual_friendship!
#user_friendship.friend.user_friendships.find_by(friend_id: current_user.id).accept_mutual_friendship!
flash[:success] = "You are now friends with #{#user_friendship.friend.name}!"
redirect_to user_friendships_path
else
flash[:error] = "That friendship could not be accepted."
end
end
def block
#user_friendship = current_user.user_friendships.find(params[:id])
if #user_friendship.block!
flash[:success] = "You have blocked #{#user_friendship.friend.name}."
else
flash[:error] = "This friendship could not be blocked."
end
redirect_to user_friendships_path
end
def new
if params[:friend_id]
#friend = User.find(params[:friend_id]).first
raise ActiveRecord::RecordNotFound if #friend.nil?
#user_friendship = current_user.user_friendships.new(friend: #friend)
else
flash[:error] = "Friend required."
end
rescue ActiveRecord::RecordNotFound
render file: 'public/404', status: :not_found
end
def create
if params[:user_friendship] && params[:user_friendship].has_key?(:friend_id)
#friend = User.find(params[:user_friendship][:friend_id])
#user_friendship = UserFriendship.request(current_user, #friend)
respond_to do |format|
if #user_friendship.new_record?
format.html do
flash[:error] = "There was a problem creating this friend request."
redirect_to user_path(#friend)
end
format.json { render json: #user_friendship.to_json, status: :precondition_failed }
else
format.html do
flash[:success] = "Friend request sent."
redirect_to user_path(#friend)
end
format.json { render json: #user_friendship.to_json }
end
end
else
flash[:error] = "Friend required"
redirect_to root_path
end
end
def edit
#friend = User.find(params[:id])
#user_friendship = current_user.user_friendships.find_by(friend_id: #friend.id).decorate
end
def destroy
#user_friendship = current_user.user_friendships.find(params[:id])
if #user_friendship.destroy
flash[:success] = "Your friendship was deleted"
end
redirect_to user_friendships_path
end
def user_friendship
params.require(:user_friendship).permit(:user_id, :friend_id, :user, :friend, :state, :user_friendship)
end
private
def friendship_association
case params[:list]
when nil
current_user.user_friendships
when 'blocked'
current_user.blocked_user_friendships
when 'pending'
current_user.pending_user_friendships
when 'accepted'
current_user.accepted_user_friendships
when 'requested'
current_user.requested_user_friendships
end
end
end
Index.html
<div class="page-header">
<h1> Friends </h1>
</div>
<div>
<strong>Friend list:</strong>
<%= link_to 'Accepted', user_friendships_path(list: 'accepted') %>
<%= link_to 'Pending', user_friendships_path(list: 'pending') %>
<%= link_to 'Requested', user_friendships_path(list: 'requested') %>
<%= link_to 'Blocked', user_friendships_path(list: 'blocked') %>
</div>
<% #user_Friendships.each do |friendship| %>
<% friend = friendship.friend %>
<div id="<%= dom_id(friendship) %>" class="friend row">
<div class="span1">
</div>
<div class="span7">
<strong><%= friend.name %></strong><br />
<%if friendship.pending? %>
<em>Friendship is pending.</em> <%=link_to "Delete request", edit_user_friendship_path(friendship.friend) %>.
<% end %>
<% if friendship.requested? %>
<em>Friendship requested.</em> <%=link_to "Accept Friendship", edit_user_friendship_path(friendship.friend) %>.
<% end %>
<% if friendship.accepted? %>
<em>Friendship started <%= friendship.updated_at %>.</em> <%= link_to "Update friendship", edit_user_friendship_path(friendship.friend) %>.
<% end %>
</div>
</div>
<% end %>
Problem solved. I forgot to add the below code into my user model. That was a complete miss on my part.
has_many :accepted_user_friendships, class_name: 'UserFriendship',
foreign_key: :user_id,
conditions: { state: 'accepted' }
has_many :accepted_friends, through: :pending_user_friendships, source: :friend

My create action can't access the .new_record? method

In a Rails 4.0 application I have a form and its corresponding create action. They both work perfectly:
view form:
<%= form_for #user_friendship, method: :post do |f| %>
<div class="form form-actions">
<%= f.text_field :friend_id, value: #friend.id %>
<%#= f.button :submit #=> This creates a User_friendship %>
<%= f.button :submit %>
<%= link_to "Cancel", profile_path(#friend.profile_name), class: 'btn' %>
</div>
<% end %>
its create action
def create
if params[:friend_id]
#friend = User.find_by_id(params[:user_friendship][:friend_id])
logger.fatal "Here is the friend:"
logger.fatal #friend.inspect
else
end
if #friend
#user_friendship = UserFriendship.request(current_user,#friend)
logger.fatal #user_friendship.inspect
# if #user_friendship.new_record?
# flash[:error] = "There was a problem creating that friend request"
# else
# flash[:success] = "Friend request sent to " + #friend.first_name
# end
redirect_to profile_path(#friend.profile_name), status: 302
else
flash[:error] = "Friend required!"
redirect_to root_path, status: 302
end
end
But when I uncomment these lines:
if #user_friendship.new_record?
flash[:error] = "There was a problem creating that friend request"
else
flash[:success] = "Friend request sent to " + #friend.first_name
end
I get this error message:
NoMethodError in UserFriendshipsController#create
undefined method `new_record?' for #<Mail::Message:0x00000104aae768>
I have no idea where is this error is coming from (is it a problem with a mailer?) so please tell me if I need to post more information.
I find that Mail::Message part really strange...what is this object?
model
def self.request(user1, user2)
friendship1 = []
transaction do
friendship1 = create!(user_id: user1.id, friend_id: user2.id, state: 'pending')
friendship2 = create!(user_id: user2.id, friend_id: user1.id, state: 'requested')
end
friendship1.send_request_email
end
def send_request_email
UserNotifier.friend_requested(id).deliver
end
mailer:
def friend_requested(user_friendship_id)
user_friendship = UserFriendship.find(user_friendship_id)
#user = user_friendship.user
#friend = user_friendship.friend
mail to: #friend.email,
subject: #user.first_name + " wants to be your friend!"
end
#user_friendship is assigned the value which is return from calling UserFriendship.request(...). It appears that method returns a mail object (are you sending an email notification there as the last line in the method?). Try returning the UserFriendship object from that method.
Edit:
Better yet, just do #user_friendship = UserFriendship.create(current_user, #friend) and then send an email in an after_create callback.
Well, you are getting a Mail::Message object in the UserFriendship.request call. Does this object have a method "new_record?" ?. Probably not.

Resources