I have this variable in my pdforms_controller that is grouping all of the pdforms based on their group_id.
#groups = Pdform.where(principal_action: 'approved', super_action: 'new').group_by(&:group_id)
> {"DSC-002"=>[#<Pdform id: 63, date_start: "2017-12-08", date_finish: "2017-12-09", location: "First test", mtg_name: "First
> test", memo: "First test", acct_num: "12312312323", sub: true,
> accepted: false, guest_id: nil, created_at: "2017-12-08 21:36:37",
> updated_at: "2017-12-21 15:43:57", user_id: 13, pdtype:
> "instructional", reason: nil, prr_requested: nil, length: "full",
> principal_action: "approved", super_action: "new", group_id:
> "DSC-002", is_group: false>],
> "DSC-001"=>[#<Pdform id: 64, date_start: "2017-12-19", date_finish: "2017-12-20", location: "test", mtg_name: "test", memo:
> "test", acct_num: nil, sub: false, accepted: false, guest_id: nil,
> created_at: "2017-12-19 14:37:48", updated_at: "2017-12-20 18:05:55",
> user_id: 13, pdtype: "instructional", reason: "Dont like\r\n",
> prr_requested: nil, length: "half", principal_action: "approved",
> super_action: "new", group_id: "DSC-001", is_group: false>, #<Pdform
> id: 65, date_start: "2017-12-19", date_finish: "2017-12-20", location:
> "group test", mtg_name: "group test", memo: "group test", acct_num:
> "", sub: false, accepted: false, guest_id: nil, created_at:
> "2017-12-19 20:20:02", updated_at: "2017-12-21 15:50:21", user_id: 13,
> pdtype: "technology", reason: "wait, huh?", prr_requested: nil,
> length: "half", principal_action: "approved", super_action: "new",
> group_id: "DSC-001", is_group: false>]}
Right now I am just calling this in my view to display this information.
<%= #groups.each do |group| %>
<%-# do something -%>
<% end %>
How can I get each record out of this array and display that data in separate columns, bootstrap cards, or whatever other container I want to use? I have never used arrays to store data so excuse me if this is either blatantly obvious or a stupid question.
When you have a hash, like { key: 'value', other_key: 'other_value' }, you can use each as the following:
# in rails console
h = { some_key: 'value', other_key: 'other_value' }
h.each do |k, v|
puts "the value for key #{k.inspect} is #{v.inspect}"
end
# it will output:
the value for key :some_key is "value"
the value for key :other_key is "other_value"
So in your case, you can simply do:
#groups.each do |group_id, pdforms|
# group_id is the key (ex: "DSC-002")
# pdforms is the value for that key (in your case: an array of Pdform records)
# in this loop you can then cycle through all `pdforms`:
pdforms.each do |pdform|
# do something with a single Pdform record
end
end
Related
I'm building a most viewed post feature for a simple blog. Each post has a view count that is increased when the Show action is called for that particular post. Then on the Dashboard , I'm trying to list the top 5 posts. So far my code works and returns an array of posts with the post with the highest number of view count being the first index and the last index in the array being the post with the lowest view count. The only thing is when I try to iterate through the array in the view , the view returns:
ERROR
undefined method `title' for nil:NilClass
WHY??? Does it have to do with the "#" infront of the object?
Heres my code.
Dashboard View
<h3> Post </h3>
<% #top_posts.each do |post| %>
<%= post.title %>
<% end %>
Controller Methods
def get_top
#top_posts = []
counts = []
#posts = Post.all
#posts.each do |post|
counts << post.view_count
end
#posts.each do |post|
if counts.max(5).include?(post.view_count)
counts.max(5).each do |n|
if n == post.view_count
#top_posts[counts.max(5).index(n)] = post
end
end
end
end
end
def dashboard
#posts = Post.all
get_top
end
The Top Podcast Array of objects
[#<Post id: 6, title: "Post 6", desc: "", tags: "", view_count: 8, s_desc: "", c_photo: nil, photos: nil, created_at: "2017-06-14 06:02:25", updated_at: "2017-06-15 01:38:40", featured: nil>, #<Post id: 3, title: "post 3", desc: "", tags: "", view_count: 5, s_desc: "", c_photo: nil, photos: nil, created_at: "2017-06-14 05:35:32", updated_at: "2017-06-14 05:35:53", featured: nil>, #<Post id: 5, title: "Post 5", desc: "", tags: "", view_count: 4, s_desc: "", c_photo: nil, photos: nil, created_at: "2017-06-14 06:02:20", updated_at: "2017-06-15 01:38:31", featured: nil>, nil, #<Post id: 4, title: "Post 4", desc: "", tags: "", view_count: 3, s_desc: "", c_photo: nil, photos: nil, created_at: "2017-06-14 05:49:29", updated_at: "2017-06-15 01:38:50", featured: nil>]
The other answer would probably solve your error, but just want to make an attempt to optimize your code.
That array, loop, etc. is unnecessary, ask your db to do that stuff and get the top posts. Fetching all posts and looping over it multiple times...nay, try the following, hopefully this is what you are looking for..
#top_posts = Post.order('view_count desc').limit(5)
That's it, your view needs no change and will work as expected.
Try:
#top_posts << post
instead of:
#top_posts[counts.max(5).index(n)] = post
You don't need to set the array index.
Suppose I have hashes of elements and I need to filter out the results based on the class names in them.
so, if records contains elements of PrivateSchool, I can pass PrivateSchool records to its respective partial.
If records contains elements of Teacher, I can pass Teacher records to its respective partial.
So, here is the code for partails:
<% if params[:tab] && params[:tab] == "featured" %>
<%= render partial: "featured", locals: {featured: #results} %>
<% elsif params[:tab] && params[:tab] == "schools" %>
<%= render partial: "schools", locals: {schools: #results} %>
<% elsif params[:tab] && params[:tab] == "playlists" %>
<%= render partial: "playlists", locals: {playlists: #results} %>
<% elsif params[:tab] && params[:tab] == "quizzes" %>
<%= render partial: "quizzes", locals: {quizzes: #results} %>
<% elsif params[:tab] && params[:tab] == "teachers" %>
<%= render partial: "teachers", locals: {teachers: #results} %>
<% end %>
If I do <%= #results.inspect%> it outputs below:
[#<LessonPlan id: 9, title: "advance java", description: "advance java",
notes: "advance java", subject_id: 2, teacher_id: 1, created_at: "2016-11-11
09:29:20", updated_at: "2016-11-11 09:29:20", is_private: true, is_publish:
false, user_id: 3, publish_date: nil, popularity_count: 0, is_special: false,
private_class_id: nil>, #<Quiz id: 1, title: "java history",
time_limit_in_minutes: 5, are_multiple_attempts_allowed: true, score_to_keep:
"highest", number_of_attempts_allowed: 4, student_see_quiz_score:
"after_each_attempt", show_one_question_at_a_time: true, is_private: false,
available_from_date_time: "2016-11-08 17:13:00", available_due_date_time:
"2016-11-10 17:18:00", instructions: "<p>java basics</p>", lesson_plan_id: 3,
user_id: 3, publish_date: "2016-11-09 12:14:04", created_at: "2016-11-09
12:14:04", updated_at: "2016-11-09 12:19:25", is_publish: true, subject_id: 3,
teacher_id: 1, popularity_count: 1, show_answers: "after_the_due_date">,
#<LessonPlan id: 4, title: "basics of java", description: "basics of java",
notes: "basics of java", subject_id: 2, teacher_id: 1, created_at: "2016-11-07
13:04:24", updated_at: "2016-11-10 10:40:54", is_private: false, is_publish:
false, user_id: 3, publish_date: "2016-11-09 08:08:41", popularity_count: 0,
is_special: false, private_class_id: nil>, #<Quiz id: 6, title: "java modern",
time_limit_in_minutes: 155, are_multiple_attempts_allowed: true,
score_to_keep: "latest", number_of_attempts_allowed: 9,
student_see_quiz_score: "after_last_attempt", show_one_question_at_a_time:
true, is_private: true, available_from_date_time: "2017-02-02 01:11:00",
available_due_date_time: "2017-02-27 01:11:00", instructions: "<p>java modern
java modern java modern java modern...", lesson_plan_id: 3, user_id: 3,
publish_date: "2016-12-22 20:37:35", created_at: "2016-12-22 20:37:35",
updated_at: "2017-02-09 20:11:38", is_publish: false, subject_id: 3,
teacher_id: 1, popularity_count: 0, show_answers: "after_the_due_date">,
#<Quiz id: 4, title: "Java quiz v1", time_limit_in_minutes: 180,
are_multiple_attempts_allowed: true, score_to_keep: "latest",
number_of_attempts_allowed: 6, student_see_quiz_score: "after_last_attempt",
show_one_question_at_a_time: false, is_private: false,
available_from_date_time: "2016-11-21 12:48:00", available_due_date_time:
"2016-11-23 12:48:00", instructions: "<p>Java quiz v1</p>\r\n<p
style=\"margin: 0px;\"><!--E...", lesson_plan_id: 8, user_id: 3, publish_date:
"2016-11-14 07:18:41", created_at: "2016-11-14 07:18:41", updated_at:
"2016-12-11 14:21:46", is_publish: false, subject_id: 3, teacher_id: 1,
popularity_count: 0, show_answers: "after_the_quiz">, #<Quiz id: 3, title:
"java basics", time_limit_in_minutes: 4, are_multiple_attempts_allowed: true,
score_to_keep: "highest", number_of_attempts_allowed: 10,
student_see_quiz_score: "after_last_attempt", show_one_question_at_a_time:
true, is_private: false, available_from_date_time: "2017-01-31 14:13:00",
available_due_date_time: "2017-02-17 14:13:00", instructions:
"<p>XXXXXXXXXXQQQQ</p>", lesson_plan_id: 8, user_id: 3, publish_date:
"2016-11-10 20:27:32", created_at: "2016-11-10 20:27:31", updated_at:
"2017-02-01 09:13:22", is_publish: false, subject_id: 3, teacher_id: 1,
popularity_count: 1, show_answers: "after_the_quiz">, #<PrivateSchool id: 18,
teacher_id: 39, user_id: 47, title: "Dr. Jasmine E McNair High School",
short_description: "Dr. Jasmine E McNair High School", price_type: "paid",
logo: "download.jpg", slug: "dr-jasmine-e-mcnair-high-school", created_at:
"2016-12-13 20:18:28", updated_at: "2016-12-13 20:18:28">]
What I really want is to filter these records per model class name so I can filtered records and send the respective records to their partials rather than just show all of them in each partial.
Currently its showing all records in one partial which is wrong I need to filter them per partial so each partial will show his results not other model.
So,
If records belongs to LessonPlan all records from LessonPlan will go in lesson plan partial.
If records belongs to Teacher all records from Teacher will go in teacher partials .
and so on.
That's my requirement.
You can try something like that :
hash = #results.group_by(&:class)
then :
hash[LessonPlan] will give you a list of all the LessonPlan
Edit :
<%= render partial: "quizzes", locals: {quizzes: hash[Quiz]} %>
Explanation :
First step. We create as Hash based by the Class of the object. To accomplish that we use the Ruby method 'group_by' for Enumerable.
#results.group_by(&:class) is equivalent of #results.group_by {|result| result[:class]}
Then we can easily access the value of each hash by the class name. hash[Quiz] will return all the Quiz objects.
Results can be filtered using the select method:
#results.select { |r| r.is_a?(LessonPlan) } # etc.
Therefore your view can look like this:
<%= render partial: "lesson_plans", locals: {
lesson_plans: #results.select { |r| r.is_a?(LessonPlan) }
} %>
When I comment out my after_save call back, my ActiveRecord associations work just fine. In Rails Console, you'd see:
> #report = Report.create :name => "foo"
=> #<Report id: 9, name: "foo", created_at: "2013-03-05 09:51:55", updated_at: "2013-03-05 09:51:55">
> #question = #report.questions.create :description => "bar"
=> #<Question id: 18, standard_id: nil, description: "bar", element_id: nil, condition_id: nil, blueprint_name: nil, blueprint_url: nil, created_at: "2013-03-05 09:52:32", updated_at: "2013-03-05 09:52:32", additive: false, instructions: nil>
> #report.questions
=> [#<Question id: 18, standard_id: nil, description: "bar", element_id: nil, condition_id: nil, blueprint_name: nil, blueprint_url: nil, created_at: "2013-03-05 09:52:32", updated_at: "2013-03-05 09:52:32", additive: false, instructions: nil>]
> #question.reports
=> [#<Report id: 9, name: "foo", created_at: "2013-03-05 09:51:55", updated_at: "2013-03-05 09:51:55">]
However, the associations stop working when I add the following after_save callback to question.rb:
def create_matching_surveys
self.reports.each do |report|
report.reviews.each do |review|
review.competitors.each do |competitor|
competitor.surveys.find_or_create_by_question_id(self.id)
end
end
end
end
Then, in Rails Console, you get:
> #report = Report.create :name => "foo"
=> #<Report id: 13, name: "foo", created_at: "2013-03-05 10:20:51", updated_at: "2013-03-05 10:20:51">
> #question = #report.questions.create :description => "bar"
=> #<Question id: 24, standard_id: nil, description: "bar", element_id: nil, condition_id: nil, blueprint_name: nil, blueprint_url: nil, created_at: "2013-03-05 10:21:02", updated_at: "2013-03-05 10:21:02", additive: false, instructions: nil>
> #report.questions
=> [#<Question id: 24, standard_id: nil, description: "bar", element_id: nil, condition_id: nil, blueprint_name: nil, blueprint_url: nil, created_at: "2013-03-05 10:21:02", updated_at: "2013-03-05 10:21:02", additive: false, instructions: nil>]
> #question.reports
=> []
This happens whether or not the report has reviews that have competitors.
The strange thing is I thought the callback was meant to happen after the question was saved? So by rights the association should save too before any of this happens, right?
How do I fix it?
UPDATE
I think I have to call the callback in the right spot in the object's life cycle, but I can't find that spot. Here's why I think this:
> #report = Report.create :name => "foo"
=> #<Report id: 20, name: "foo", created_at: "2013-03-05 12:29:35", updated_at: "2013-03-05 12:29:35">
> #question = #report.questions.create :description => "bar"
=> #<Question id: 31, standard_id: nil, description: "bar", element_id: nil, condition_id: nil, blueprint_name: nil, blueprint_url: nil, created_at: "2013-03-05 12:30:14", updated_at: "2013-03-05 12:30:14", additive: false, instructions: nil>
> #question.reports
=> []
> #question.update_attributes :description => "foo"
=> true
> #question.reports
=> [#<Report id: 20, name: "foo", created_at: "2013-03-05 12:29:35", updated_at: "2013-03-05 12:29:35">]
BTW, the method is now in question_observer.rb:
class QuestionObserver < ActiveRecord::Observer
def after_save(model)
model.reload
model.reports.reload
model.reports.each do |report|
report.reviews.each do |review|
review.competitors.each do |competitor|
competitor.surveys.find_or_create_by_question_id(model.id)
end
end
end
return true
end
end
The answer was to use a neat new callback hook called after_commit which was introduced with Rails 3.
See http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html#method-i-after_commit.
The only issue is after_commit doesn't work "out of the box" with transactional fixtures, but there are plenty of solutions out there, and I found this one worked well for me: https://supportbee.com/devblog/2012/01/14/testing-after_commitafter_transaction-with-rspec/
I want to update a table but the update SQL is not performed so the changes has no effect.
Details:
Originally issue.name us 'issue'. I want to change to 'qqqqqqqqqqqq'.
Controller:
def update
if params['cancel']
redirect_to(#issue)
return
end
#issue = Issue.find(params[:id])
logger.debug "original object"
logger.debug "#{#issue.to_yaml}"
logger.debug 'bulk attribute settings...'
#issue.attributes= params[:issue]
logger.debug "after bulk settings"
logger.debug "#{#issue.to_yaml}"
#issue.events.build(:note=>params[:issue][:description],:verb=>'Edited', :changes=>#issue.textalize_changes)
if #issue.save
logger.debug "after save"
logger.debug "#{#issue.to_yaml}"
redirect_to(#issue)
else
render :action => "edit"
end
end
One additional code fregment might be interesting is the textalize_changes:
def textalize_changes
r = ""
if changed?
changes.keys.each do |k|
r << "#{k.humanize} changed "
r << "from `#{translate(k,changes[k][0])}` "
r << "to `#{translate(k,changes[k][1])}`"
r << "<br/>"
end
end
r unless r.blank?
end
The result:
until the line #issue.save everything looks correct. I have checked that #issue contains all the changes i have made.
on the user interface no changes I have notified.
in the log no update SQL is visible. all relevant select and insert is presented but no update - so no change in table issues
even textalize_changes has not realize and changes in the object when checking for that (changed?)
If I manually change the attribute in at source code level by name=XXX it is working.
I don't know what to check or review at all. The code is so simple that i have no idea at all.
Here is the log of the operation:
original object
--- !ruby/object:Issue
attributes:
name: OTTO TEST 2
assigned_to: "29"
updated_at: 2010-12-16 10:25:28
project_id: "1"
current_estimate:
lft: "1"
original_estimate:
priority:
id: "10"
version_id:
area_id:
description:
worktype_id: "2"
status_id: "5"
rgt: "2"
parent_id:
created_at: 2010-05-21 07:37:15
fixed_in_version_id:
attributes_cache: {}
bulk attribute settings...
WARNING: Can't mass-assign these protected attributes: description
[4;36;1mIssue Load (0.0ms)[0m [0;1mSELECT "lft", "rgt", "parent_id" FROM "issues" WHERE ("issues"."id" = 10) [0m
after bulk settings
--- !ruby/object:Issue
area:
assigned_user:
attributes:
name: qqqqqqqqqq
assigned_to: "29"
updated_at: 2010-12-16 10:25:28
project_id: "1"
current_estimate:
lft: "1"
original_estimate:
priority:
id: "10"
version_id:
area_id:
description:
worktype_id: "2"
status_id: "5"
rgt: "2"
parent_id:
created_at: 2010-05-21 07:37:15
fixed_in_version_id:
attributes_cache: {}
changed_attributes: {}
children:
events:
fixed_in_version:
iterations:
marked_for_destruction: false
parent:
project:
status:
timelogs:
version:
work_items:
worktype:
[4;35;1mEvent Create (0.0ms)[0m [0mINSERT INTO "events" ("updated_at", "verb", "external", "issue_id", "note", "changes", "user_id", "created_at") VALUES('2010-12-16 10:33:08', 'Edited', 'f', 10, '', NULL, 1, '2010-12-16 10:33:08')[0m
after save
[4;36;1mEvent Load (16.0ms)[0m [0;1mSELECT * FROM "events" WHERE ("events".issue_id = 10) ORDER BY id ASC, created_at ASC[0m
--- &id001 !ruby/object:Issue
area:
assigned_user:
attributes:
name: qqqqqqqqqq
assigned_to: "29"
updated_at: 2010-12-16 10:25:28
project_id: "1"
current_estimate:
lft: "1"
original_estimate:
priority:
id: "10"
version_id:
area_id:
description:
worktype_id: "2"
status_id: "5"
rgt: "2"
parent_id:
created_at: 2010-05-21 07:37:15
fixed_in_version_id:
attributes_cache: {}
Technical info:
Op system: winXP
rails: rails 2.3.4
Additional info:
I have a bulk operation with the same purpose which is working correctly. I really don't know the differences:
def update_multiple
if params['cancel']
redirect_to issues_path
return
end
#issues = Issue.find(params[:issue_ids])
#issues.each do |issue|
issue.attributes= params[:issue].reject {|k,v| v.blank? }
issue.apply_template_on_name_change
issue.events.build(:note=>params[:issue][:description],:verb=>"Edited", :changes=>issue.textalize_changes)
issue.save!
end
flash[:notice]="Issues updated!"
redirect_to issues_path
end
Additional info:
If I replace #issue.attributes= params[:issue] by #issue.attributes= params[:issue].reject {|k,v| v.blank? } it apply changes and working. But it is not the one I really want. I want to change everything at once. I am going crazy.
Can you try save with exclamation, like #issue.save! to see the errors.
I have found the issue in awesome nested set.
This plugin reloads the object just before executing nested set operations.: I have changed the controller in the following way:
#issue.parent_issue= params[:issue][:parent_issue]
#issue.attributes= params[:issue].reject {|k,v| 'parent_issue'==k }
this the best solutions now.
note: parent_issue is for setting the parent of the given entity and using the same form as for the rest of the attributes.
I'm calling update_attributes but it doesn't seem to be changing the object.
def add_to_vote_count(increment)
vc = vote_count ? vote_count : 0
puts "CALLED a_t_v_c(#{increment}), NEW VOTE COUNT SHOULD BE #{vc + increment}"
self.update_attributes(:vote_count => (vc + increment))
end
Here's some console testing:
ruby-1.8.7-p299 > p = Factory(:playlist)
=> #<Playlist id: 56, user_id: 0, message: "Lorem ipsum dolor sit amet, consectetur adipisicing...", title: "Ipsum Dolor", flag: 2, created_at: "2010-08-12 18:18:51", updated_at: "2010-08-12 18:18:51", moderation_score: 0, photo_file_name: nil, photo_content_type: nil, photo_file_size: nil, photo_updated_at: nil, category_id: nil, widget_id: 22100001, permalink: #<ActiveSupport::Multibyte::Chars:0x102feba48 #wrapped_string="ipsum-dolor-27">, cached_tag_list: "", vote_count: 0>
ruby-1.8.7-p299 > p.vote_count
=> 0
ruby-1.8.7-p299 > p.votes
=> []
ruby-1.8.7-p299 > p.votes << Vote.new(:vote => true)
CALLED a_t_v_c(1), NEW VOTE COUNT SHOULD BE 1
VOTE CREATED
=> [#<Vote id: 235, vote: true, voteable_id: 56, voteable_type: "Playlist", voter_id: nil, voter_type: nil, created_at: "2010-08-12 18:19:09", updated_at: "2010-08-12 18:19:09">]
ruby-1.8.7-p299 > p.votes
=> [#<Vote id: 235, vote: true, voteable_id: 56, voteable_type: "Playlist", voter_id: nil, voter_type: nil, created_at: "2010-08-12 18:19:09", updated_at: "2010-08-12 18:19:09">]
ruby-1.8.7-p299 > p.vote_count
=> 0
ruby-1.8.7-p299 > p
=> #<Playlist id: 56, user_id: 0, message: "Lorem ipsum dolor sit amet, consectetur adipisicing...", title: "Ipsum Dolor", flag: 2, created_at: "2010-08-12 18:18:51", updated_at: "2010-08-12 18:18:51", moderation_score: 0, photo_file_name: nil, photo_content_type: nil, photo_file_size: nil, photo_updated_at: nil, category_id: nil, widget_id: 22100001, permalink: #<ActiveSupport::Multibyte::Chars:0x102feba48 #wrapped_string="ipsum-dolor-27">, cached_tag_list: "", vote_count: 0>
Any idea why nothing is getting saved? I don't get any errors, and calling the methods normally returns the 'correct' results.
ruby-1.8.7-p299 > p.update_attributes(:vote_count => 100)
=> true
ruby-1.8.7-p299 > p.vote_count
=> 100
ruby-1.8.7-p299 > p.add_to_vote_count(10)
CALLED a_t_v_c(10), NEW VOTE COUNT SHOULD BE 110
=> true
ruby-1.8.7-p299 > p.vote_count
=> 110
The only difference I can see is that add_to_vote_count is being called by the Vote class in its after_create method. As you can see from the output, though, add_to_vote_count is definitely getting called.
#in vote.rb
def after_create
voteable.add_to_vote_count( vote ? 1 : -1 )
puts "\n\nVOTE CREATED\n\n"
end
Edit: Actually, it turns out that the object is getting updated, but my reference is not. That is to say, p returns the old version with no votes, but Playlist.find(p.id) returns the correct one. I assume this is due to caching (Rails doesn't want to hit the database again for an item it should have in memory), so how do I force Rails to realize that stuff changed?
I really don't know if this is going to help you, but you can use increment instead of update_attributes.
def add_to_vote_count(increment)
self.increment!(:vote_count, increment)
end
If you try, please let me know if this worked :]
Edit
I believe the reload method can solve your problem!
My guess is that your object is failing validation and that's why its not saving. Try using update_attributes! with the exclamation so it throws and error and you can see whats up.
Good luck.