I wanna use model attribute in view Rails - ruby-on-rails

I am trying to use attribute value in model but its not working..
I have three models:
models/resident.rb
class Resident < ActiveRecord::Base
belongs_to :hostel
has_one :user,dependent: :delete
end
models/user.rb
class User < ActiveRecord::Base
belongs_to:resident
end
models/hostel.rb
class Hostel < ActiveRecord::Base
has_many :residents
has_one :rate_card,dependent: :delete
end
Schema
Resident
create_table "residents", force: :cascade do |t|
t.string "room_number"
t.string "roll_number"
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "hostel_id"
end
User
create_table "users", force: :cascade do |t|
t.string "roll_number"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "resident_id"
end
Hostel
create_table "hostels", force: :cascade do |t|
t.string "hostel"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Now i want to use the hostel attribute value in users/show.html.erb
I am able to do this :
<%if #user.resident.roll_number=="101303110"%>
if the roll number is present then returning true..
but if is use :
<%if #user.resident.hostel=="J"%>
and if J is a hostel present in Hostel model then it is returning false.
But when we put<%#user.resident.hostel%> in show.html.erb then it is showing value J.
How should I use related models attributes in each other view?

Given your associations, #user.resident.hostel would load a hostel. But you want to compare the hostel string on the hostel. Therefore your comparison should be:
<% if #user.resident.hostel.hostel == 'J' %>
Explanation:
#user # returns your a user
#user.resident # follows `belongs_to :resident` and
# returns a resident
#user.resident.hostel # follows `belongs_to :hostel` on the resident and
# returns a hostel
#user.resident.hostel.hostel # returns the value store in the `hostel`
# column of that `hostel`
Btw. I would argue that chaining calls like that violates the Law of Demeter. But it is hard to suggest any alternative without having more insights into your app.

Related

accepts_nested_attributes - ActiveRecord::UnknownAttributeError

I have a very simple model that each event has many forexes. I am trying to create a nested form to create new event with a bunch of forexes in a go.
class Event < ActiveRecord::Base
has_many :forexes
accepts_nested_attributes_for :forexes
end
class Forex < ActiveRecord::Base
belongs_to :event
end
The schema is like this:
ActiveRecord::Schema.define(version: 20180505093823) do
create_table "events", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "base"
end
create_table "forexes", force: :cascade do |t|
t.string "code"
t.float "rate"
t.integer "event_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "forexes", ["event_id"], name: "index_forexes_on_event_id"
end
And then I tried to create new objects using the following code in rails console. It fails.
Event.new( name: "11", base: "HKD", forexes_attributes: [ {code: "RMB", rate:1}, {code: "CNY",rate:2}])
It throws me back with this error.
ActiveRecord::UnknownAttributeError: unknown attribute 'forexes_attributes' for Event.
I know this is quite a basic question. And I have tried many different ways after researching in different places. I couldn't debug it. Appreciate your help.
In your Event controller you need to include the forexes_attributes in event_params method as along with default one
def event_params
params.require(:event).permit(forexes_attributes: Forexes_attribute_names.map(&:to_sym).push(:_destroy))
end

find a record that match another one (from another table)

I have three tables user, event, expected_event
My event are scrapped (every day with a rake task) from another
website
A user can create expected_event
So What I want to do is:
When a new event is found I want it to be compared to the Users expected_event...
If an event matches to any users expected_event then the users receive an email with the matching event (event.department, event.location_name)
I want to compare event.department to expected_event.department
I don't know how to do this...
expected_event.rb
class ExpectedEvent < ApplicationRecord
belongs_to :user
validates :department, presence: true
end
user.rb
class User < ApplicationRecord
has_many :expected_events
end
In the event model I have some methode to retreive city_name, location_nameand department
class Event < ApplicationRecord
def department
self.city[/\(.*?\)/].gsub(/[()]/, "").to_i
end
def city_name
self.city[/^[^\(]+/].rstrip!
end
def location_name
self.city[/\|(.*)/].gsub("|", "").strip
end
end
schema.rb
ActiveRecord::Schema.define(version: 20171210203403) do
create_table "events", force: :cascade do |t|
t.datetime "date"
t.string "city"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "nickname"
####
end
create_table "expected_events", force: :cascade do |t|
t.integer "department"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_expected_events_on_user_id"
end
end
EDIT
Is it correct if I add something like this to my user model?
has_many :matching_events, through: :events, source: :expected_events
When a new event is created, why don't you just query for ExpectedEvent records with matching paramters. Something like
event = Event.create(event_params)
if ExpectedEvent.where(city: event.city, ...).any?
#send email to user about the event
end

Rails - collection_select does not select a values from tables having translations

I am relatively new to RoR.
This works nicely:
<td><%= collection_select :competitions_members, :member_id, Member.all, :id, :first_name %></td>
This one picks no value (actually all such calls to tables with translations):
<td><%= collection_select :competitions_members, :tull_id, Tull.all, :id, :name %></td>
seeded data in competitions_members table
Member can be involved in many competition. Basically I have N:M relationship between members and competitions via competitions_members table.
Tull is a dictionary. Value to be set during the process of assigning members to a competition.
Data model classes:
class Member < ApplicationRecord
has_and_belongs_to_many :competitions
end
class Competition < ApplicationRecord
has_and_belongs_to_many :members
end
class CompetitionsMember < ApplicationRecord
end
Tull table has also translations in separate table.
class Tull < ApplicationRecord
translates :name
has_many :competitions_members
# separate different localizations of the record
def cache_key
super + '-' + Globalize.locale.to_s
end
end
Relevant schema.db excerpt
create_table "members", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "competitions", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "competitions_members", force: :cascade do |t|
t.integer "member_id"
t.integer "competition_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "tull_id"
t.index ["tull_id"], name: "index_competitions_members_on_tull_id"
end
create_table "tull_translations", force: :cascade do |t|
t.integer "tull_id", null: false
t.string "locale", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name"
t.index ["locale"], name: "index_tull_translations_on_locale"
t.index ["tull_id"], name: "index_tull_translations_on_tull_id"
end
create_table "tulls", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Any help apreciated. I just realized this might be connected with translated tables somehow.
class Tull < ApplicationRecord
has_many :translations
translates :name, :fallbacks_for_empty_translations => true
attr_accessible :translations_attributes
end
Try to execute below code in rails console:
Tull.first.translations - If this gives you translation records that means the associations are correct.
Now check at view side, how would you generate attributes for multilingual stuffs. I would suggest to use globalize_accessors.
Please send me the codebase.

Rails - One-direction table association - accessing data issue

I have two models:
class Order < ActiveRecord::Base
belongs_to :user
has_one :order_type
end
class OrderType < ActiveRecord::Base
belongs_to :order
end
my schema.rb:
create_table "order_types", force: :cascade do |t|
t.string "ort_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "orders", force: :cascade do |t|
t.string "ord_name"
t.date "ord_due_date"
t.integer "user_id"
t.integer "ordertype_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "orders", ["ordertype_id"], name: "index_orders_on_ordertype_id"
add_index "orders", ["user_id"], name: "index_orders_on_user_id"
There is only one-direction association between them. The Order model has a column "ordertype_id" that links to the appropriate order_type.
My question is, what is the best practice to access the ort_name value for each #order in a view.
Currently, I am using:
<p>
<strong>Ord type:</strong>
<% OrderType.where(id: #order.ordertype_id).each do |t| %>
<%= t.ort_name %>
<% end %>
</p>
This solution results in many code repetitions. How I should change that? Can somebody advise, as I am not so experienced yet?
I tried this code, but it did not work:
#orders.order_type
There are many problems which you should address. It's ok to be a beginner, just take yourself time to learn and improve.
Schema
First off, your schema is set up badly. If you want to limit the order type to certain values, you should do this with a validation.
class Order
TYPES = %w[foo bar three four five]
validates :order_type, inclusion: { in: TYPES }
end
This way, you can easily add values in the future, and remove the complexity of adding a new model and its relations.
Column Names
Secondly, you should revise your column names. ord_name and ord_due_date is bad, it leads to ugly calls like order.ord_name. You should drop the prefix ord, it's superfluous.
Both steps would lead to this schema.rb
create_table "orders", force: :cascade do |t|
t.string "name"
t.date "due_date"
t.integer "user_id"
t.string "order_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Logic placement
My final advice is to never call queries from your view. Logic should always be in the controller / model & passed to the view via instance variables.
This is a big no no in rails:
<% OrderType.where(id: #order.ordertype_id).each do |t| %>
...
<% end %>
In the end, accessing the type is simply accomplished with:
#order.order_type
Update your Order model to this:
class Order < ActiveRecord::Base
belongs_to :user
has_one :order_type, foreign_key: 'ordertype_id`
end
then order_type should be easily accessible:
#order.order_type.ort_name

How do you add data to a model's has_many relationship programatically in Rails?

In this app I have three models - Players, Teams and Rounds.
class Player < ActiveRecord::Base
has_and_belongs_to_many :teams
end
class Team < ActiveRecord::Base
has_and_belongs_to_many :players
belongs_to :round
end
class Round < ActiveRecord::Base
has_many :teams
end
In each round, a different amount of teams will be generated based on the number of players that are sent in (Players are to be persistent, but in each round you can select the ones that will actually play this time around). Once the teams are created, they are populated with the list of players for this round.
In my RoundsController i've setup a method which gets called in the create action for a new Round.
def createTeams
totalPlayers = #players.length
noOfTeams = totalPlayers/5
while (noOfTeams > 0) do
team = Team.new
team.round = #round
team.save
noOfTeams -= 1
end
i = totalPlayers - 1
while (i >= 0) do
#round.teams.each do |team|
player = #players.at(i)
player.team = team
player.save
i -= 1
end
end
At the moment I can't actually set the team's round to the current round, I get a 'can't write unknown attribute round_id' error. Am I going about this the right way? Have I setup my relationships correctly? I thought I would be able to do something like #round.teams.build(team) or #round.teams.add(team)... Any help appreciated, sorry if this is a duplicate but I've been searching around for a while without any luck.
Here's the Schema:
ActiveRecord::Schema.define(version: 20150310124456) do
create_table "players", force: :cascade do |t|
t.string "first_name"
t.string "surname"
t.string "email"
t.string "phone"
t.integer "goals"
t.integer "clean_sheets"
t.integer "wins"
t.integer "draws"
t.integer "losses"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "players_teams", id: false, force: :cascade do |t|
t.integer "player_id"
t.integer "team_id"
end
add_index "players_teams", ["player_id"], name: "index_players_teams_on_player_id"
add_index "players_teams", ["team_id"], name: "index_players_teams_on_team_id"
create_table "rounds", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "teams", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
You are missing a round_id from Team.
In a migration you can simply use
add_column :teams, :round_id, :integer
to fix this. An id like this is required if you have a belongs_to in a model.
And to add to a round
#round.teams << team

Resources