Access attributes from an associated model rails 3 - ruby-on-rails-3

I want to display the ingredients for each recipe on the recipe show view, the ingredients are in a separate model called ingredients but have a belongs_to relationship with the recipe model
So when i call user name for example i use
#recipe.user.name
This is because the attributes are within the recipe model, I have a method in the recipe helper like so
def ingredient_names(ingredients)
if ingredients
ingredient_array = ingredients.map {|ing| ing.ingredient_name}
ingredient_array.join("\n")
end
end
So i thought i could call
#recipe.ingredient_names
but i get an undefined method error..
Then i thought i had to pass the params ingredient_name (name of the column)
#recipe.ingredient_names(:ingredient_name)
but still get undefined method error
and when i do
<%= #recipe.ingredients(:ingredient_name) %>
i get this as the output
[#<Ingredient id: 71, ingredient_name: "Ingredient 1", recipe_id: 56, created_at: "2012-11-29 19:29:25", updated_at: "2012-12-02 16:29:58">, #<Ingredient id: 76, ingredient_name: "ingredient 2", recipe_id: 56, created_at: "2012-12-02 16:29:59", updated_at: "2012-12-02 16:29:59">, #<Ingredient id: 77, ingredient_name: "ingredient 3", recipe_id: 56, created_at: "2012-12-02 16:29:59", updated_at: "2012-12-02 16:29:59">]
so how do i call the attributes for another model when i have the relationship belongs_to and has_many. Simple question i guess but cant figure it out
thanks

Figured out the solution, i needed to access the method first
<%= ingredient_names #recipe.ingredients(:ingredient_name)

Related

select vs distinct vs uniq?

I am confused by Ruby's ActiveRecord uniq method. I am using it to try to get back an array of complete objects, not just a particular field.
In my Padrino app script, which saves newspaper names and scores as Score objects, the uniq method by attribute on an ActiveRecord Relation is not working, and neither is distinct, with or without SQL syntax. Can anyone explain what is going on?
class Score < ActiveRecord::Base
def self.from_today
self.where('created_at > ?', Date.today)
end
end
scores = Score.from_today
scores.class
=> Score::ActiveRecord_Relation
scores.first
=> #<Score id: 123, score: -2.55, source: "Mail", created_at: "2016-08-11 04:29:24", updated_at: "2016-08-11 04:29:24">
scores.map(&:source)
=> ["Mail", "Guardian", "Telegraph", "Independent", "Express", "Mail"]
scores.uniq(:source).count
=> 6
scores.distinct(:source).count
=> 6
scores.select('distinct (SOURCE)').count
=> 5 #AHA, it works!
scores.select(:source).distinct
=> #<ActiveRecord::Relation [#<Score id: nil, source: "Telegraph">, #<Score id: nil, source: "Mail">, #<Score id: nil, source: "Independent">, #<Score id: nil, source: "Express">, #<Score id: nil, source: "Guardian">]>
#oops, no it doesn't
In Rails 5 distinct has no parameter. In Rails 4.2 the parameter is only true or false. When true, return distinct records, when false return none distinct records. uniq is in this case only an alias for distinct
So for Rails 4
scores.select(:source).distinct.count is what you want. This restricts distinct to column source

With ActionCable, is there a way to count how many subscribers from inside a channel?

For an app I'm building, I have a "lobby" page where people configure which area they'd like to join. Pretty basic.
I'd like to have a running total of active consumers that are currently subscribed to the channel for this page, so that users know whether or not there's other people around to interact with.
Is there an easy way to do this?
I defined a helper method:
app/channels/application_cable/channel.rb
module ApplicationCable
class Channel < ActionCable::Channel::Base
def connections_info
connections_array = []
connection.server.connections.each do |conn|
conn_hash = {}
conn_hash[:current_user] = conn.current_user
conn_hash[:subscriptions_identifiers] = conn.subscriptions.identifiers.map {|k| JSON.parse k}
connections_array << conn_hash
end
connections_array
end
end
end
Now you can call connections_info anywhere inside your derived channel. The method returns an informational array of data about all the available server socket connections, their respective current_users and all their current subscriptions.
Here is an example of my data connections_info returns:
[1] pry(#<ChatChannel>)> connections_info
=> [{:current_user=>"D8pg2frw5db9PyHzE6Aj8LRf",
:subscriptions_identifiers=>
[{"channel"=>"ChatChannel",
"secret_chat_token"=>"f5a6722dfe04fc883b59922bc99aef4b5ac266af"},
{"channel"=>"AppearanceChannel"}]},
{:current_user=>
#<User id: 2, email: "client1#example.com", created_at: "2017-03-27 13:22:14", updated_at: "2017-04-28 11:13:37", provider: "email", uid: "client1#example.com", first_name: "John", active: nil, last_name: nil, middle_name: nil, email_public: nil, phone: nil, experience: nil, qualification: nil, price: nil, university: nil, faculty: nil, dob_issue: nil, work: nil, staff: nil, dob: nil, balance: nil, online: true>,
:subscriptions_identifiers=>
[{"channel"=>"ChatChannel",
"secret_chat_token"=>"f5a6722dfe04fc883b59922bc99aef4b5ac266af"}]}]
You can then parse this structure the way you want and extract the desired data. You can distinguish your own connection in this list by the same current_user (the current_user method is available inside class Channel < ActionCable::Channel::Base).
If a user connects twice (or more times), then corresponding array elements just double.
Yup there is one :
In your app/channel/what_so_ever_you_called_it.rb:
class WhatSoEverYouCalledItChannel < ApplicationCable::Channel
def subscribed
stream_from "your_streamer_thingy"
#subscriber +=1 #<==== like this
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
#subscriber -=1 #<===== like this
end
def send_message(data)
your_message_mechanic
end
Setup a variable increasing in subscribed
and decreasing in unsubscribed.
You may want store the value in your 'lobby' model , in this case '#subscriber' may be called #lobby.connected_total, i dont know, make this fit your needs.
But this is a way to keep track of number of stream.
Njoy

Joining Unrelated Tables in Rails

Bottom line - I want to join two database tables together that do not "belong to" each other but do have a common field.
After some research on StackOverflow, I found some solutions to similar problems that use SQL directly, like so:
Address.joins('INNER JOIN phones on addresses.person_id = phones.person_id').select("addresses.*, phones.*").limit(1)
When I use the above statement in my rails console, however, it performs the following SQL query:
Address Load (0.3ms) SELECT addresses.*, phones.* FROM `addresses` INNER JOIN phones on addresses.person_id = phones.person_id LIMIT 1
and returns the following data (censored for privacy reasons):
=> #<ActiveRecord::Relation [#<Address id: 0001, created_at: "YYYY-MM-DD hh:mm:ss", updated_at: "YYYY-MM-DD hh:mm:ss", description: nil, line1: "123 Evergreen Terrace", line2: "", line3: "", city: "Springfield", state: "IL", country: "USA", zip: "11111", building_number: "001", person_id: 1, address_type: "Home", primary: false, show: nil, job_id: nil, room_number: "001", source: "HR", effective_date: "YYYY-MM-DD">]>
Not a single field from the Phone table made it into the final record.
Do I have to make these unrelated tables "belong to" each other to make them work? Like -
class Address < ActiveRecord::Base
belongs_to :person
end
class Phone < ActiveRecord::Base
belongs_to :person
belongs_to :address
end
Or can I do what I want without modifying my models' relationships?
The data might not be visible in the query, but the record will respond to those fields that were fetched by the query, meaining if the phone record has a number attribute for example, doing a call to .number will respond with the fetched number
address = Address.joins(....).select('*').first
address.number # => this will print the phone number of the phone record.

Rails difference in exception debug output for same object

I have a User model and a List model in my app.
pages_controller.rb
class PagesController < ApplicationController
def home
if user_signed_in?
#lists = current_user.lists
# raise #lists.inspect
#new_list = current_user.lists.build
end
end
end
pages/home.html.erb
<%= raise #lists.inspect %>
Now, my current user has no lists associated with him .
When I uncomment the 3rd line in "Pages#home" raise #lists.inspect I get the output like so : []
But, when I comment that line out, then the exception inside home.html.erb is raised , and its output is like so : [#<List id: nil, name: nil, description: nil, user_id: 1, created_at: nil, updated_at: nil>]
Why is there a difference in output for the same #lists.inspect line ?
EDIT : When I use #lists = current_user.lists.all instead of #lists = current_user.lists then I get an empty array at both places . Why the difference in behavior between the 2 codes ?
Because you build lists in the controller after the first raise:
#new_list = current_user.lists.build
It's the same code, but the data is different, because you did something to it.

Get rspec controller test to do a shallow comparison of BigDecimals

I have an rspec controller with the test:
it "assigns all rate_card_details as #rate_card_details" do
rate_card_detail = FactoryGirl.create(:rate_card_detail)
get :index, {}, valid_session
assigns(:rate_card_details).should eq([rate_card_detail])
end
For most models, this works fine. However, in this case, the rate field is a decimal. This causes the rspec comparison to (for some reason) compare 1 instance of BigDecimal with another, including its location in memory. Here is the error:
Failure/Error: assigns(:rate_card_details).should eq([rate_card_detail])
expected: [#<RateCardDetail rate_card_id: 1, item_id: 1, rate: #<BigDecimal:7f82dcdb0ae0,'0.6941E2',18(18)>, created_at: "2013-06-05 18:12:53", updated_at: "2013-06-05 18:12:53">]
got: [#<RateCardDetail rate_card_id: 1, item_id: 1, rate: #<BigDecimal:7f82dc9a74d0,'0.6941E2',18(18)>, created_at: "2013-06-05 18:12:53", updated_at: "2013-06-05 18:12:53">]
The 2 BigDecimals have the same value, but are different objects. Is there a way to get rspec to treat these as equal when doing a comparison?
it's not pretty but this works with me
it "assigns all rate_card_details as #rate_card_details" do
rate_card_detail = FactoryGirl.create(:rate_card_detail)
get :index, {}, valid_session
assigns(:rate_card_details).first.attributes.values.each_with_index do |rcd,i|
r_c_d = rate_card_detail[i]
if rcd.is_a?BigDecimal
rcd = rcd.to_s
r_c_d = r_c_d.to_s
end
expect(rcd).to eq(r_c_d)
end
end