How to group ruby array based on id in the hash - ruby-on-rails

I have two models post and topic which has a one to many relation
#Post.rb
class Post < ApplicationRecord
belongs_to :topic
validates :topic_id, presence: true
validates :title, presence: true
validates :body, presence: true
end
if i have an array of posts by calling Post.all for example
#<ActiveRecord::Relation [#<Post id: 1, title: "Rails Code", body: "class TopicsController < ApplicationController\r\n ...", created_at: "2018-05-22 09:34:15", updated_at: "2018-05-22 09:34:15", topic_id: "2">,
#<Post id: 2, title: "Post with tags", body: "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq...", created_at: "2018-05-22 11:48:54", updated_at: "2018-05-22 11:48:54", topic_id: "2">,
#<Post id: 3, title: "12hello world12", body: "12312sdfsdfsdsdsdsd31231231231231", created_at: "2018-05-23 12:54:02", updated_at: "2018-05-23 12:54:02", topic_id: "2">,
#<Post id: 4, title: "12hello world12", body: "12312sdfsdfsdsdsdsd31231231231231", created_at: "2018-05-23 12:54:09", updated_at: "2018-05-23 12:54:09", topic_id: "1">,
#<Post id: 5, title: "12hellsdssdo world12", body: "12312sdfsdfsdsdsdsd31231231231231", created_at: "2018-05-23 12:54:15", updated_at: "2018-05-23 12:54:15", topic_id: "1">]>
is there a way i could group them by their topic_id so i could display them topic by topic
example
Topic - 1
post 1 post2 post 3
Topic -2
post4 post5

Use this:
Post.all.group_by(&:topic_id).each do |topic_id, posts|
...
end

Found the answer.
You can do it using ruby's Enumerable#group_by:
post.group_by{|post| post.topic_id}

Related

Bring the user name when query an item in Rails

I have an endpoint the returns all the comments on a blog. I would like to have the name of the user that made the comment. Is there a way to bring it all together when hitting that comments endpoint or do I have to make another query for each comment?
def comments
#comments = #blog.comments
render json: { comments: #comments }
end
This is what doing #blog.comments returns
[#<Comment id: 1, content: "This is a very good post", created_at: "2020-09-11 01:55:56", updated_at: "2020-09-11 01:55:56", blog_id: 3, user_id: 1>, #<Comment id: 2, content: "I agree with all of this", created_at: "2020-09-11 01:55:56", updated_at: "2020-09-11 01:55:56", blog_id: 3, user_id: 1>, #<Comment id: 3, content: "I don't agree with all of this", created_at: "2020-09-11 01:55:56", updated_at: "2020-09-11 01:55:56", blog_id: 3, user_id: 1>]>
Assuming you have a users table with a field users.name, and a belongs_to :user relationship on your model comment:
Just replace the line
#comments = #blog.comments
with
#comments = #blog.comments.select('comments.*, users.name').joins(:user)

rspec undefined method `id' for nil:NilClass

require 'rails_helper'
feature "comment" do
given(:current_user) do
create(:user)
end
given(:undertaking) do
create(:undertaking)
end
background do
login_as(current_user)
end
scenario "can create comment" do
#below two because undertaking = user_id:2 & asking_id:1
create(:user)
create(:asking)
p undertaking
p Asking.find(1)
p User.find(2)
p User.find(1)
p Undertaking.all
visit undertaking_path(undertaking)
expect(current_path).to eq undertaking_path(1)
within("form#undertake-form-test") do
fill_in "content" , with: "heyheyhey"
end
click_button 'Send'
expect(page).to have_content 'heyheyhey'
end
end
This is spec/features/comment_spec.rb.
and this below is result command rspec.
#<Undertaking id: 1, title: "MyString", content: "MyText", result: false, user_id: 2, asking_id: 1, created_at: "2016-12-13 15:07:08", updated_at: "2016-12-13 15:07:08">
#<Asking id: 1, content: "MyText", fromlang: "MyString", tolang: "MyString", usepoint: 1, finished: false, title: "MyString", deadline: nil, user_id: 1, created_at: "2016-12-13 15:07:08", updated_at: "2016-12-13 15:07:08">
#<User id: 2, email: "shiba.hayato2#docomo.ne.jp", created_at: "2016-12-13 15:07:08", updated_at: "2016-12-13 15:07:08", provider: nil, uid: nil, name: "Shiruba", occupation: "大学生", age: 10, sex: "男性", content: "heyheyheyeheyeheye", skill: "日本語検定3級", picture: "/assets/default_user.jpg", point: 500, country: "Japan", language1: "Japanese", language2: "Korea", language3: "English">
#<User id: 1, email: "shiba.hayato1#docomo.ne.jp", created_at: "2016-12-13 15:07:08", updated_at: "2016-12-13 15:07:08", provider: nil, uid: nil, name: "Shiruba", occupation: "大学生", age: 10, sex: "男性", content: "heyheyheyeheyeheye", skill: "日本語検定3級", picture: "/assets/default_user.jpg", point: 500, country: "Japan", language1: "Japanese", language2: "Korea", language3: "English">
#<ActiveRecord::Relation [#<Undertaking id: 1, title: "MyString", content: "MyText", result: false, user_id: 2, asking_id: 1, created_at: "2016-12-13 15:07:08", updated_at: "2016-12-13 15:07:08">]>
F
Failures:
1) comment can create comment
Failure/Error: <%= #undertaking.id %>
ActionView::Template::Error:
undefined method `id' for nil:NilClass
and this below is undertaking_controller.rb.
class UndertakingController < ApplicationController
def show
#undertaking=Undertaking.find(params[:id])
#comment=Comment.new do |c|
c.user=current_user
end
end
end
and this below is undertaking/show.html.erb.
<%= #undertaking.id %>
Why do I have the error? Why #undertaking is nil in view although Undertaking.first is not nil in spec/features/comment_spec.rb?Please help me.
I think it has to do with the naming used for your controller . The convention is undertakings/show.html.erb for the view instead of undertaking/show.html.erb . I would also use
class UndertakingsController < ApplicationController
instead of
class UndertakingController < ApplicationController
Finally I would check that all my routes also have the correct naming. Hope that helps. Good luck

Rails 4 combining output from models

I am a beginner, so this question maybe very elementary. I appreciate any help. I have three models - one Metal that does a query of a database to get a price and another QuoteMetal which is nested through has_many and accepts_nested_attributes_for in Lead. I need the results of the query conducted through the Metal model to be available in the lead collection so I can display the results in the view.
My question: how do I get those query results (specifically the price attribute) to be in the Lead instance variable. Of if not the lead instance variable - what is the best way to display the results. Below is my code.
class LeadsController < ApplicationController
def index
#lead = Lead.new
#quote_metal = #lead.quote_metals.build
#quote_melee = #lead.quote_melees.build
#quote_diamond = #lead.quote_diamonds.build
end
def create
#raise params.inspect
#lead = Lead.new(lead_params)
#qm = #lead.quote_metals.map { |f| Metal.calculate_metal(f).first}
##lead.quote_metals.each do |f|
# f[:price] = #qm[:price].to_i
#end
#lead = Lead.create!(lead_params)
end
def show
end
private
def lead_params
params.require(:lead).permit([:name, :email, :phone, :zip, :note, :method,
quote_metals_attributes: [:id, :metal, :weight, :unit, :price],
quote_melees_attributes: [:shape, :quality, :quantity, :totalweight, :size],
quote_diamonds_attributes: [:shape, :size, :color, :clarity]
])
end
end
Metal Model:
class Metal < ActiveRecord::Base
enum metal: {platinum: 1, palladium: 2, "10_karat_gold": 3, "14_karat_gold": 4,
"18_karat_gold": 5, "22_karat_gold": 6, silver: 7}
enum unit: {pennyweight: 1, grams: 2, ounce: 3, pound: 4}
attr_accessor :weight
#Validations
validates :metal, :unit, :weight, presence: true
scope :calculate_metal, ->(quote_metal) {
where(metal: QuoteMetal.metals[quote_metal.metal],
unit: QuoteMetal.units[quote_metal.unit])
}
scope :multiple, ->(quote_metal){
}
end
Create.html.erb
<pre>
<%= #qm.inspect %>
<br>
<%= #lead.quote_metals.inspect %>
<br>
<%= #qm.inspect %>
<br>
<%= #qm2.inspect %>
</pre>
Output:
[#<Metal id: 11, metal: 2, unit: 2, price: #<BigDecimal:7ff01dac4be8,'0.1367E2',18(18)>, created_at: "2015-05-26 10:36:38", updated_at: nil, weight: nil>, #<Metal id: 11, metal: 2, unit: 2, price: #<BigDecimal:7ff01da96450,'0.1367E2',18(18)>, created_at: "2015-05-26 10:36:38", updated_at: nil, weight: nil>]
#<ActiveRecord::Associations::CollectionProxy [#<QuoteMetal id: 231, lead_id: 176, metal: 2, unit: 2, price: nil, weight: #<BigDecimal:7ff01cc71320,'0.1E1',9(18)>, quote: nil, created_at: "2015-07-14 18:26:46", updated_at: "2015-07-14 18:26:46">, #<QuoteMetal id: 232, lead_id: 176, metal: 2, unit: 2, price: nil, weight: #<BigDecimal:7ff01ca49d90,'0.2E1',9(18)>, quote: nil, created_at: "2015-07-14 18:26:46", updated_at: "2015-07-14 18:26:46">]>
[#<Metal id: 11, metal: 2, unit: 2, price: #<BigDecimal:7ff01dac4be8,'0.1367E2',18(18)>, created_at: "2015-05-26 10:36:38", updated_at: nil, weight: nil>, #<Metal id: 11, metal: 2, unit: 2, price: #<BigDecimal:7ff01da96450,'0.1367E2',18(18)>, created_at: "2015-05-26 10:36:38", updated_at: nil, weight: nil>]
[[#<Lead id: nil, name:..., note: "asdf", created_at: nil, updated_at: nil>, #<Metal id: 11, metal: 2, unit: 2, price: #<BigDecimal:7ff01dac4be8,'0.1367E2',18(18)>, created_at: "2015-05-26 10:36:38", updated_at: nil, weight: nil>]]
Thank you.

ActiveRecord not retrieving all models

I have 2 models, Car and Person. Each person can have many cars. I have loaded some data through from seed.rb but when I try Car.find_by(owner_id: 1) in the console, I see just one car. When I am expecting 2 cars because I assigned 2 cars to one particular Person. Why am I just seeing one car?
car.rb (model)
class Car < ActiveRecord::Base
belongs_to :owner, class_name: "Person", foreign_key: "owner_id"
has_many :place_rents
validates :owner, presence: true
validates :registration_number, presence: true
validates :model, presence: true
end
person.rb
class Person < ActiveRecord::Base
has_many :cars, foreign_key: "owner_id"
has_many :parkings, foreign_key: "owner_id"
validates :first_name, presence: true
end
seed.rb
people = Person.create([{first_name: "Emmanuel", last_name: "Hayford"}, {first_name: "Steve", last_name: "Jobs"},
{first_name: "James", last_name: "Bond"}, {first_name: "Michael", last_name: "Jordan"}])
addresses = Address.create([{street: "Limanowskiego", city: "Kraków", zip_code: "98-734"}, {street: "Zeromskiego",
city: "Wrocław", zip_code: "45-622"}, {street: "Chopin", city: "Gdańsk", zip_code: "98-734"},
{street: "Putin", city: "Opole", zip_code: "90-938"}])
cars = Car.create([{owner: Person.first, model: "BMW", registration_number: "UJ8483"}, {owner: Person.second, model: "Lambo", registration_number: "JH4857"},
{owner: Person.second, model: "Jaguar", registration_number: "DW3455"}, { owner: Person.second, model: "Ferrari", registration_number: "KP8734"},
{owner: Person.first,model: "Bugatti Veyron", registration_number: "ZK9837"}])
parkings = Parking.create([{kind: "indoor", hour_price: 45.50, day_price: 200, places: 5, owner: Person.first, address_id: Address.first},
{kind: "outdoor", hour_price: 20.50, day_price: 150.00, places: 10, owner: Person.second, address_id: Address.second},
{kind: "street", hour_price: 270.50, day_price: 89.45, places: 7, owner: Person.second, address_id: Address.second},
{kind: "private", hour_price: 40.50, day_price: 30.45, places: 2, owner: Person.find(2), address_id: Address.find(2)},])
place_rents = PlaceRent.create([{parking: Parking.first, car: Car.first, start_date: Time.now, end_date: Time.now + 3.days, price: 30}])
2.1.4 :023 > Car.all
Car Load (0.5ms) SELECT "cars".* FROM "cars"
=> #<ActiveRecord::Relation [#<Car id: 1, registration_number: "UJ8483", model: "BMW", owner_id: 1, created_at: "2014-11-10 00:10:26", updated_at: "2014-11-10 00:10:26">, #<Car id: 2, registration_number: "JH4857", model: "Lambo", owner_id: 2, created_at: "2014-11-10 00:10:26", updated_at: "2014-11-10 00:10:26">, #<Car id: 3, registration_number: "DW3455", model: "Jaguar", owner_id: 2, created_at: "2014-11-10 00:10:26", updated_at: "2014-11-10 00:10:26">, #<Car id: 4, registration_number: "KP8734", model: "Ferrari", owner_id: 2, created_at: "2014-11-10 00:10:26", updated_at: "2014-11-10 00:10:26">, #<Car id: 5, registration_number: "ZK9837", model: "Bugatti Veyron", owner_id: 1, created_at: "2014-11-10 00:10:26", updated_at: "2014-11-10 00:10:26">]>
2.1.4 :024 > Car.find_by(owner_id: 1)
Car Load (0.6ms) SELECT "cars".* FROM "cars" WHERE "cars"."owner_id" = 1 LIMIT 1
=> #<Car id: 1, registration_number: "UJ8483", model: "BMW", owner_id: 1, created_at: "2014-11-10 00:10:26", updated_at: "2014-11-10 00:10:26">
2.1.4 :025 >
You misunderstand how find_by works:
find_by(*args)
Finds the first record matching the specified conditions.
find_by only gets one record from the database, hence the LIMIT 1 in the SQL it generates. If you want to find several things, then use where:
Car.where(owner_id: 1)
or, since you have the associations set up, use Person#cars:
person = Person.find(1)
cars = person.cars
Car.find_by_owner_id(1) is the same as Car.where(owner_id: 1).first so basically it returns one record rather than an array of record. Car.where(owner_id: 1) will get you your two records.

How do I output in Views just the variables' values I want in Ruby On Rails?

Now in my application.html.erb in views folder, I wrote this.
<p>List of all post IDs: <%= Post.all.each {|i| print i.id } %></p>
I would like it to output just the post.id of each post. But instead it shows this
List of all post IDs: [#<Post id: 1, title: "Our First Post", content: "Content for our first post", created_at: "2012-11-24 11:22:02", updated_at: "2012-11-26 17:40:54", user_id: 1>, #<Post id: 3, title: "Our Second Post", content: "Content for our second post", created_at: "2012-11-24 11:51:32", updated_at: "2012-11-26 17:41:33", user_id: 2>, #<Post id: 8, title: "Our Second Post", content: "Content of Our mandatory Second Post", created_at: "2012-11-24 19:42:02", updated_at: "2012-11-27 20:46:57", user_id: 1>, #<Post id: 10, title: "C Post", content: "Hi I'm Cee nice to meet you", created_at: "2012-11-26 17:51:20", updated_at: "2012-11-26 17:51:20", user_id: 3>, #<Post id: 20, title: "11", content: "11", created_at: "2012-11-27 19:58:48", updated_at: "2012-11-27 19:58:48", user_id: 4>, #<Post id: 21, title: "22", content: "22", created_at: "2012-11-27 19:58:53", updated_at: "2012-11-27 19:58:53", user_id: 4>, #<Post id: 25, title: "I'm Super Singha!", content: "Yessar!!!", created_at: "2012-11-27 20:45:07", updated_at: "2012-11-27 20:45:07", user_id: 6>, #<Post id: 26, title: "Should this be a blog or a forums or a whatever-wha...", content: ";asljdfi;asfi;asdf;lasbfurbofioboboeifhosdsdbvisbvw...", created_at: "2012-11-27 20:46:28", updated_at: "2012-12-02 14:17:14", user_id: 1>, #<Post id: 27, title: "Hullow", content: "Yoyoyo", created_at: "2012-11-30 07:35:38", updated_at: "2012-11-30 07:35:54", user_id: 6>, #<Post id: 649, title: "um", content: "hey", created_at: "2012-11-30 12:20:58", updated_at: "2012-11-30 12:20:58", user_id: 2>, #<Post id: 82692, title: "LALALALAL", content: "hiopsdahfiosadhfioahfio", created_at: "2012-12-02 13:59:04", updated_at: "2012-12-02 14:22:41", user_id: 2>, #<Post id: 82693, title: "ggg", content: "fff", created_at: "2012-12-02 14:29:42", updated_at: "2012-12-02 14:29:42", user_id: 2>, #<Post id: 82694, title: "sick", content: "sick", created_at: "2012-12-02 14:41:32", updated_at: "2012-12-02 14:41:32", user_id: 5>]
I have tried, puts instead of print, that doesn't work either.
Further: I would also like to make a link_to each post show page from the intended result, how can I achieve that?
Here's my repo: https://github.com/nixor/cpblog , here's heroku site: http://still-plains-5469.herokuapp.com/
Thanks.
The problem is with how you are using the ERB tags here:
<%= Post.all.each {|i| print i.id } %>
Whenever you use <%=, the result of the block will be rendered. In your case, Post.all.each {} returns an array object, which is exactly what you are seeing in your rendered HTML.
In order to print out each item, you will need to loop through the items using <% and then print out what you want using <%=.
<p>List of all post IDs:
<% Post.all.each |post| do %>
<%= link_to post.id, post_path(post) %>
<% end %>
</p>
<p>List of all post IDs:
</p>
<%= Post.all.each do |e| %>
<p>
<%= e.Id %>
<p>
<%= link_to "Show", e %>
<% end %>

Resources