I've been trying to deal with this to no avail. It's driving me nuts. Usually, I can sleep on something like this and realize it was a typo in the morning. But I can't sleep until I figure this out - catch 22. Anyway, I have an index of questions being displayed, the title of each question is a link to itself. Nothing surprising there. And it works on local host. When I deploy to heroku, it shows that it's leading me to the correct link and I have it routed correctly when I hover the links. (ie, myapp.herokuapp.com/questions/2). I definitely have the links set to question_path(question) in the block. yet, when I click the link, it takes me to the questions_path, right back to the index of questions. It's driving me mad. Anyone have a problem like this before?
index.html.erb View:
<% if #quests.present? %>
<% #quests.each do |question| %>
<div class="booyah-box col-xs-10 col-xs-offset-1">
<center>
<bptitle>
<%= link_to question.qtitle.html_safe, question_path(question) %>
</bptitle>
<br />
<bpauthor> A question by <%= question.user.firstname %> <%= question.user.lastname %>, from
<%= question.user.organization.name %></bpauthor>
</center>
<br />
<%= question.qbody.split[0..10].join(" ").html_safe %>... <br /><br />
Answers: <%= question.answers.count %><br />
</div>
<% end %>
<% else %>
<p>There are no posts containing the term(s) <%= params[:search] %>.</p>
<% end %>
</center>
questions_controller:
def index
if params[:search] != nil
#quests = Question.search(params[:search]).order("created_at DESC")
else
#quests = Question.all.order('created_at DESC')
end
end
def show
#question = Question.find(params[:id])
#answer = Answer.new
#faveanswer = Favanswer.new
#ans = Answer.find(params[:id])
#qids = []
#qaids = []
Favanswer.all.each do |favanswer|
#qids << favanswer.question_id
#qaids << [favanswer.question_id, favanswer.answer_id]
end
end
Question model:
class Question < ActiveRecord::Base
include Bootsy::Container
mount_uploader :bootsy, BootsyUploader
belongs_to :user
has_many :answers
has_one :favanswer
def self.search(search)
where("qtitle LIKE ? OR qbody LIKE ?", "%#{search}%", "%#{search}%")
end
end
Please tell me I have a typo. I will kiss your feet if you help. I need sleep.
Editing with my heroku logs per Andrew's comment below:
2016-08-01T13:54:20.800626+00:00 app[web.1]: Started GET "/questions/3" for 162.244.49.116 at 2016-08-01 13:54:20 +0000
2016-08-01T13:54:20.803208+00:00 app[web.1]: Processing by QuestionsController#show as HTML
2016-08-01T13:54:20.803238+00:00 app[web.1]: Parameters: {"id"=>"3"}
2016-08-01T13:54:20.806102+00:00 app[web.1]: User Load (1.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
2016-08-01T13:54:20.809813+00:00 app[web.1]: Question Load (0.8ms) SELECT "questions".* FROM "questions" WHERE "questions"."id" = $1 LIMIT 1 [["id", 3]]
2016-08-01T13:54:20.833346+00:00 app[web.1]: Redirected to http://mypretendapp.herokuapp.com/questions
Depending on your Heroku configuration, you can either face a 404 error or being redirected (to home by default if I remember well) when the page you're looking for does not exist (either the routing is bad or your controller raises a ActiveRecordNotFound error). If it works in localhost, I would rather explore my second guess. You should check your question object that you are passing to your url helper. Is it correct ? Does it have an id ?
Have you tried replacing the variable question in
<%= link_to question.qtitle.html_safe, question_path(question) %>
with #question? If I'm reading it correctly, it would be pointing it back at #quests because of your do loop instead of #question.
Related
I have 3 models
pre_writing.rb
class PreWriting < ApplicationRecord
belongs_to :students, optional: true
belongs_to :classrooms, optional: true
belongs_to :options, optional: true
end
student.rb
has_many :pre_writings
classroom.rb
has_many :pre_writings
has_many :classroom_students
in classroom/show.html.erb
<% #classroom.students.each do |element| %>
<% if #classroom.user_id == current_user.id %>
<%= element.pre_writings.ids.first.updated_at %>
<% end %>
<% end %>
I get an error
undefined method `updated_at' for nil:NilClass
and if I try
<%= element.pre_writings.ids.first %>
I can get the id
and in console if I try
classroom.students.find(86).pre_writings.first.updated_at
I get the value
Student Load (0.1ms) SELECT "students".* FROM "students" INNER JOIN "classroom_students" ON "students"."id" = "classroom_students"."student_id" WHERE "classroom_students"."classroom_id" = ? AND "students"."id" = ? LIMIT ? [["classroom_id", 7], ["id", 86], ["LIMIT", 1]]
PreWriting Load (0.2ms) SELECT "pre_writings".* FROM "pre_writings" WHERE "pre_writings"."student_id" = ? ORDER BY "pre_writings"."id" ASC LIMIT ? [["student_id", 86], ["LIMIT", 1]]
=> Tue, 19 Dec 2017 23:50:52 UTC +00:00
Can someone tell me why I am getting undefined method error
The problem in your code is that by using .ids you are returning an array of pre_writings ids and then with .first you are selecting the first id and trying to access a not defined method (updated_at) for that id type (probably integer).
Also, when you are executing queries it is recommended to check if something is actually returned or the result set is empty. That is the case with the .first ActiveRecord method and by checking if the query has returned results you are avoiding the nil:NilClass access errors.
What you might want to do is something like:
<% #classroom.students.each do |element| %>
<% if #classroom.user_id == current_user.id %>
<% #first = element.pre_writings.first %>
<% if #first.present? %>
<%= #first.updated_at %>
<% else %>
- no record
<% end %>
<% end %>
<% end %>
EDIT:
You can also condense
<% #first = element.pre_writings.first %>
<% if #first.present? %>
<%= #first.updated_at %>
<% else %>
- no record
<% end %>
into
<%= element.pre_writings.first&.updated_at || "no record" %>
The &. is called the Safe Navigator syntax that allows you to check for children attributes without having to do clumsy if-checks for existence of parents all the way down. This line will show the updated_at time, or if it's nil, will show no record instead.
element.pre_writings.ids.first is an integer value and it doesnt have method updated_at
maybe you want to write <%= element.pre_writings.first.updated_at %>
You are getting undefined method error because the method is being called on nil.
You can only call updated_at on a pre_writing, so you need to make sure you have one first.
Then you need to call the method on the actual object rather than the id.
That can be done with something like
<%= element.pre_writings.first.try(:updated_at) %>
Using try will prevent the error if pre_writings.first is nil.
Or you can add the check in your if:
<% if #classroom.user_id == current_user.id && element.pre_writings.any? %>
<%= element.pre_writings.first.updated_at %>
You may also want to rename element to student for readability since it's the student that has many pre_writings.
In my RoR application, I have an update_multiple method that updates multiple records with the user's inputs. However, for some reason I get the error ActiveModel::ForbiddenAttributesError despite using strong params. Can someone please help me fix this?
The update_multiple method in Recipients_Controller is as follows:
def update_multiple
#email = Email.find_by_id(params[:email_id])
if Recipient.update(params[:recipient].keys, params[:recipient].values)
#listofcontacts = Recipient.where("id in (?)", params[:recipient].keys)
#account = Account.find_by_id(#email.account_id)
#listofcontacts.each do |f|
recipient_message = #email.message
recipient_message = recipient_message.gsub("VAR1", f.var1)
contact = Contact.find_by_id(f.contact_id)
#unsubscribe = Rails.application.message_verifier(:unsubscribe).generate(contact.id)
UserEmails.send_email(#email, #account, contact.email, #unsubscribe, recipient_message).deliver_now
end
flash[:notice] = "recipients were updated"
redirect_to root_path
else
render 'edit_multiple'
end
end
private
def recipient_params
params.require(:recipient).permit(:contact_id, :group_id, :email_id, :var1, :var2, :var3)
end
This method takes the user input from this form:
<%= form_for :recipient, :url => update_multiple_recipients_path, :html => { :method => :put } do %>
<fieldset>
<table cellpadding="0" cellspacing="0" border="0" class="table table-striped table-bordered" id="example">
<thead>
<tr>
<th>Contact</th>
<% if #email_message.upcase.include? "VAR1" %><th>VAR1</th><% end %>
</tr>
</thead>
<tbody>
<%= hidden_field_tag :email_id, #email %>
<% #recipients.each do |recipient| %>
<tr class="odd gradeX">
<%= fields_for "recipient[]", recipient do |recipient_fields| %>
<td><%= recipient_fields.label recipient.contact.firstname %> <%= recipient_fields.label recipient.contact.surname %></td>
<% if #email_message.upcase.include? "VAR1" %><td><%= recipient_fields.text_field :var1, :required => true, :maxlength => 20 %></td><% end %>
<% end %>
</tr>
<% end %>
</tbody>
</table></br>
<%= submit_tag 'Send Email', {:class => 'btn btn-primary'} %></br>
<%= link_to "Back", edit_email_path(#email) %>
</fieldset>
<% end %>
The development.log reads this:
Started PUT "/recipients/update_multiple" for ::1 at 2017-03-03 09:33:10 +0000
Processing by RecipientsController#update_multiple as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"BJtQ56CW169tJ0Yqlc7BZNZk8SiTCauvkpNkXRUqVv4WESSS/DGFVDe3uQnfTxxDgif8lbg8THtmxHT9bOh0zw==", "email_id"=>"292", "recipient"=>{"635"=>{"var1"=>"ben"}}, "commit"=>"Send Email"}
[1m[36mEmail Load (0.0ms)[0m [1mSELECT "emails".* FROM "emails" WHERE "emails"."id" = ? LIMIT 1[0m [["id", 292]]
[1m[35mRecipient Load (1.0ms)[0m SELECT "recipients".* FROM "recipients" WHERE "recipients"."id" = ? LIMIT 1 [["id", 635]]
[1m[36m (0.0ms)[0m [1mbegin transaction[0m
[1m[35m (0.0ms)[0m rollback transaction
Completed 500 Internal Server Error in 5ms (ActiveRecord: 1.0ms)
ActiveModel::ForbiddenAttributesError (ActiveModel::ForbiddenAttributesError):
app/controllers/recipients_controller.rb:15:in `update_multiple'
Rendered C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/actionpack-4.2.6/lib/action_dispatch/middleware/templates/rescues/_source.erb (0.0ms)
Rendered C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/actionpack-4.2.6/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (4.0ms)
Rendered C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/actionpack-4.2.6/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (1.0ms)
Rendered C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/actionpack-4.2.6/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (1459.1ms)
Rendered C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/web-console-2.3.0/lib/web_console/templates/_markup.html.erb (0.0ms)
Rendered C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/web-console-2.3.0/lib/web_console/templates/_inner_console_markup.html.erb within layouts/inlined_string (0.0ms)
Rendered C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/web-console-2.3.0/lib/web_console/templates/_prompt_box_markup.html.erb within layouts/inlined_string (0.0ms)
Rendered C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/web-console-2.3.0/lib/web_console/templates/style.css.erb within layouts/inlined_string (0.0ms)
Rendered C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/web-console-2.3.0/lib/web_console/templates/console.js.erb within layouts/javascript (1449.1ms)
Rendered C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/web-console-2.3.0/lib/web_console/templates/main.js.erb within layouts/javascript (0.0ms)
Rendered C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/web-console-2.3.0/lib/web_console/templates/error_page.js.erb within layouts/javascript (0.0ms)
Rendered C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/web-console-2.3.0/lib/web_console/templates/index.html.erb (3305.2ms)
Where it says app/controllers/recipients_controller.rb:15:in 'update_multiple', it is pointing to the line if Recipient.update(params[:recipient].keys, params[:recipient].values)
I really cannot figure out why I am getting this error. Can someone please help me?
I have looked at various other SO questions and they seem to have been solved by strong_params, but mine already has strong_params declared and isn't working.
The problems is this line:
if Recipient.update(params[:recipient].keys, params[:recipient].values)
You are passing params directly to the update method. You need to pass recipient_params into update:
if Recipient.update(recipient_params.keys, recipient_params.values)
Update
However, from your logs, it is apparent that params[:recipient] is returning a hash containing id/attribute pairs, not a single set of attributes. So you'll need to permit the attributes for each recipient id passed in params. I think this code should do it:
private
def recipient_params
params.require(:recipient).permit(permit_for_each_recipient)
end
def permit_for_each_recipient
params[:recipient].keys.inject({}){|h,k| h[k] = attributes_to_permit; h}
end
def attributes_to_permit
[:contact_id, :group_id, :email_id, :var1, :var2, :var3]
end
EDITING ANSWER AFTER COMMENTS
First of all, some good docs To help you to understand better how to use strong parameters.
Now, let's try to refactor a bit your code. Remember, methods larger than 4 lines are more risky to hide mistakes, avoid them if you can!
This is your code, I changed nothing except I moved some chunks of code into sub-methods
def update_multiple
#this cannot work because there is no instance to update
if Recipient.update(params[:recipient].keys, params[:recipient].values)
send_unsuscribe_emails
flash[:notice] = "recipients were updated"
redirect_to root_path
else
render 'edit_multiple'
end
end
private
def recipient_params
params.require(:recipient).permit(:contact_id, :group_id, :email_id, :var1, :var2, :var3)
end
def send_unsuscribe_emails
#email = Email.find_by_id(params[:email_id])
#this cannot work because params[:recipient].keys does not return a list of ids (probably you want womethink like recipients_params[:contact_id])
#listofcontacts = Recipient.where("id in (?)", params[:recipient].keys)
#account = Account.find_by_id(#email.account_id)
#listofcontacts.each do |f|
send_unsuscribe_email(f)
end
end
def send_unsuscribe_email(f)
recipient_message = #email.message.gsub("VAR1", f.var1)
contact = Contact.find_by_id(f.contact_id)
#unsubscribe = Rails.application.message_verifier(:unsubscribe).generate(contact.id)
UserEmails.send_email(#email, #account, contact.email, #unsubscribe, recipient_message).deliver_now
end
and now the solution could be like this
def update_multiple
#listofcontacts = Recipient.where("id in (?)", recipients_params[:contact_id])
if #listofcontacts.update(recipient_params)
send_unsuscribe_emails
flash[:notice] = "recipients were updated"
redirect_to root_path
else
render 'edit_multiple'
end
end
private
def recipient_params
params.require(:recipient).permit(:contact_id, :group_id, :email_id, :var1, :var2, :var3)
end
def send_unsuscribe_emails
#email = Email.find_by_id(params[:email_id])
#account = Account.find_by_id(#email.account_id)
#listofcontacts.each do |f|
send_unsuscribe_email(f)
end
end
def send_unsuscribe_email(f)
recipient_message = #email.message.gsub("VAR1", f.var1)
contact = Contact.find_by_id(f.contact_id)
#unsubscribe = Rails.application.message_verifier(:unsubscribe).generate(contact.id)
UserEmails.send_email(#email, #account, contact.email, #unsubscribe, recipient_message).deliver_now
end
Of course I cannot test it so, probably it will crash somewhere, but more or less this is the idea.
I'm new to Rails and am trying to create a view form_for which adds data in two different models. I've looked at stack overflow posts about multiple models, and I've used a fields_for call to submit the information to the second model. However, my form submission only processes the form_for data, and not the fields_for. Please advise on how I would fix this. My two models are for users and schools (with the goal of someone registering their school and their own information, then being able to log in and attach that school to that adviser)
View code:
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#user) do |f| %>
<%= fields_for(#school, :url => {:controller => "advisers",
:action => "new_school"}) do |s| %>
... fields...
<% end %>
<legend>Primary Adviser Information</legend>
... forms ...
<%= f.hidden_field :access_level, :value => "Adviser" %>
<p> </p>
<div class="col-md-12">
<%= f.submit "Register", class: "btn btn-primary" %>
</div>
<% end %>
</div>
</div>
</div>
Advisers Controller:
def new
#user = User.new
#school = School.new
end
def new_school
#school = School.new(school_params)
#school.save
end
Routes:
resources :advisers do
collection do
post :new_school
end
end
Output:
Started POST "/users" for 24.13.7.99 at 2015-07-16 19:41:37 +0000
Processing by UsersController#create as HTML
Parameters: (params here)
(0.1ms) begin transaction
(inserts user here)
(17.1ms) commit transaction
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 6]]
Redirected to https://pennmc2-mdmorant.c9.io/adviser
Notice that it only activates the User post but not the advisers post.
Use accept_nested_attributes_for inside on of your models - Advisor/User? like this
accepts_nested_attributes_for :school
Getting fields_for and accepts_nested_attributes_for to work with a belongs_to relationship
I'm trying to save a form, and I am so lost on why it refuses to save. Does anybod have a clue what might be wrong?
Here's the form code:
<%= form_for #service, url: services_path do |f| %>
<% #profiles.each do |profile| %>
<%= f.text_field :service_id, value: "#{profile.service_id}" %>
<div class="media">
<a class="media-left" href="#">
<%= image_tag profile.avatar, height: '45', width: '45', class: 'img-circle' %>
</a>
<div class="media-body">
<h4 class="media-heading"><%= profile.service_username %></h4>
<%= profile.service %>
</div>
</div>
<% end %>
<%= f.submit %>
<% end %>
and
#service = current_user.services.new
the association between them are:
user has_many :services
service belongs_to :user
and the services controller create looks like this:
def create
#service = current_user.services.new(service_params)
if #service.save
flash[:notice] = "success"
redirect_to root_url
else
flash[:alert] = "Unable to add"
redirect_to :back
end
end
my logs say:
Started POST "/services" for 127.0.0.1 at 2015-01-17 18:09:44 -0800
Processing by ServicesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"lsW5aVuVUCQrHsaCo+uxbR11sF3mph3lTnM8O/Dtxn8=", "service"=> {"service_id"=>"2967861508"}, "commit"=>"Create Service"}
User Load (0.8ms) SELECT "users".* FROM "users" WHERE "users"."id" = 30 ORDER BY "users"."id" ASC LIMIT 1
(0.2ms) BEGIN
(0.2ms) ROLLBACK
Redirected to http://localhost:3000/schedules
Completed 302 Found in 9ms (ActiveRecord: 1.1ms)
Oops, minor edit below (#service.errors instead of #validation.errors):
From your logs, you can see that you got into the controller create method and the save failed. This is usually a validation problem but I can't tell from what you posted. I would put #service.errors into the flash instead of just "unable to add". This should help you and future users see what's going on when the create fails.
I have Realization model:
# encoding : utf-8
class Realization < ActiveRecord::Base
attr_accessible :city, :street, :title, :work, :photo, :date
has_attached_file :photo
end
Controller:
# encoding : utf-8
class RealizationsController < ApplicationController
before_filter :admin_required, :except => [:index,:show]
# GET /realization/new
def new
#realization = Realization.new
#realization.date = Time.now.__send__(:to_date).to_s
end
# POST /realization
def create
#realization = Realization.new(params[:realization])
if #realization.save
redirect_to #realization, notice: 'realization was successfully created.'
else
render action: "new"
end
end
(...) others
View of form:
<%= form_for #realization, :html => { :multipart => true } do |f| %>
<% if #realization.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#realization.errors.count, "error") %> prohibited this realization from being saved:</h2>
<ul>
<% #realization.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
(...)
<div class="field">
<%= f.file_field :photo %>
</div>
<div class="actions">
<%= f.submit "Submit" %>
</div>
<% end %>
And routes :
resources :realizations
And WEBrick server info is that:
Started POST "/realizacje" for 127.0.0.1 at 2013-04-12 12:26:35 +0200
Processing by RealizationsController#index as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"zK5jP4ChBBY+R21TjrZkp4xGvCHViTFJ+8Fw6Og28YY=", "realization"=>{"title"=>"wwwwww", "street"=>"", "city"=>"", "work"=>"", "date"=>"2013-04-12"}, "commit"=>"Submit"}
(1.0ms) SELECT COUNT(*) FROM "realizations"
Realization Load (2.0ms) SELECT "realizations".* FROM "realizations" ORDER BY created_at DESC LIMIT 7 OFFSET 0
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
Rendered realizations/index.html.erb within layouts/application (156.0ms)
Completed 200 OK in 340ms (Views: 333.0ms | ActiveRecord: 4.0ms)
While I use the form and push the submit it redirects/randers realizations/index without notice or errors even!
I have completely no idea why? Especialy that it worked before...
Maybe javascript added later on may be the reason?
Paperclip works well in update so it isn't it...
You might check your new action to see what you're passing in to the form_for.
You want to be passing in a brand new instance of your Realization model.
i.e. in the new action you should have a line that reads #realization = Realization.new
The reason I suggest this is because form_for calls a method (#new_record?) on the object you give it and will submit a post or put request depending on whether that method call returns true or false.