How to make a relation between two table using has_one but none of them stores id of its adjacent table - ruby-on-rails

I have a table name Strategy which looks like this:
+---+ +----+ +---+
|id | | a | | b
+---+ +----+ +---+
|1 | | 1 | | 2 |
|2 | | 2 | | 3 |
|3 | | 2 | | 4 |
|4 | | 4 | | 1 |
|5 | | 4 | | 4 |
+---+ +----+ +---+
and I have a class name Plan which looks like:
class Plan < ActiveRecord::Base
attr_accessible :a, :b
has_one :strategy ...................
end
Now I want to fill this empty has-one relation. Strategy table has column a and b and two column will always have different combination as shown in table. Now I dont know how to build a relation ship on between two table because Strategy table doesn't belong to Plan nor Plan table store strategy table id. Strategy table only contains some static values. But Plan has some a and b value and I want the id of Strategy Table on the basis of plan's a and b value using has_one relation. Is it possible in rails to do that or I need to follow some old logic.

You can build an association manually.
in your Plan model
def strategy
#strategy ||= Strategy.where("a = ? AND b = ?", a, b).first
end
this will let you reference my_plan.strategy in your code
EDIT answer updated to include Chandranshu's excellent suggestions... memoization and handling the case of more than one strategy with duplicate a, b values

Related

How to set another column with the value of the primary key on create

When creating a record I want to set a column called original_id to the value of its primary key (in this case id). In essence, the rows will become hierarchal and they will look like this:
| id | original_id |
| -- | ----------- |
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| .. | 1 |
| 42 | 42 |
| 43 | 42 |
The model will look like this:
class AccountTransaction < ApplicationRecord
belongs_to :original,
class_name: 'AccountTransaction',
foreign_key: :original_id
end
It's easy to create the record then update like this:
record = AccountTransaction.create
record.update(original: record)
But I am looking for a more elegant solution, one that doesn't require two database transactions. Thanks for your help.
You could do something with an after_create callback.
class AccountTransaction < ApplicationRecord
after_create :upate_original_id
def update_original_id
update_attribute(original_id: id)
end
end

Rails validation In attribute table

i am new to ROR.
i am building a classified ads app, i have the following tables in my database:
(some fields have been removed for simplicity)
Table Uers
This table stores all the users.
user_id
name
email
password
Table Ads
This table stores all the ads.
ad_id
users_user_id (FK)
title
desc
cat_id (FK)
created_at
Sample data:
------------------------------------------------------------------------------
| ad_id | users_user_id | title | desc | cat_id | created_at |
------------------------------------------------------------------------------
| 1 | 1 | iphone 4 | brand new | 2 | 30-11-2015 |
------------------------------------------------------------------------------
Table categories
This table stores all the available categories. cat_id in the ads table relates to cat_id in this table.
cat_id
category
parent_cid
Sample data:
-------------------------------------------
|cat_id| category | parent_cid |
-------------------------------------------
|1 | Electronics | NULL |
|2 | Mobile Phone | 1 |
|3 | Apartments | NULL |
|4 | Apartments - Sale | 3 |
-------------------------------------------
Table ads_attribute
This table contains all the available attributes for a particular category. Relates to categories table.
attr_id
cat_id (FK)
attr_label
attr_name
Sample data:
-----------------------------------------------------------
|attr_id | cat_id | attr_label | attr_name |
-----------------------------------------------------------
|1 | 2 | Operating System | Operating_System |
|2 | 2 | Is Touch Screen | Touch_Screen |
|3 | 2 | Manufacturer | Manufacturer |
|4 | 3 | Bedrooms | Bedrooms |
|5 | 3 | Total Area | Area |
|6 | 3 | Posted By | Posted_By |
-----------------------------------------------------------
Table ads_attr_value
This table stores the attribute value for each ad in ads table.
attr_val_id
attr_id (FK)
ad_id
attr_val
Sample data:
---------------------------------------------
|attr_val_id | attr_id | ad_id | attr_val |
---------------------------------------------
|1 | 1 | 1 | Ios 8 |
|2 | 2 | 1 | 1 |
|3 | 3 | 1 | Apple |
---------------------------------------------
What is the best way (the rails way) to validate the data before storing it in the the ads_attr_value table, given the fact that the values would be in select fields and the user can change them easily for example from Ios 8 to "blabla".
I've thought of storing all the possible values for each attribute in a new table and then check if a value sent by the user exist in that table before storing it in the ads_attr_value. what do you think? I am sure that there is a better way.thanks for sharing.
The rails way would probably to define your relationships with ActiveRecord associations : http://guides.rubyonrails.org/association_basics.html.
Therefore you could easily define on your model
class AdsAttrVal < ActiveRecord::Base
belongs_to :ad
validates :ad, presence: true
end
However please keep in mind that rails way to store an id of the table is to name it "id" and not "model_id" like you did ("user_id", "id"). My exemple suppose that the rails way is respected...
You have to specify the validations you want inside <yourModel>.rb (the model file) . For exame if you want to validate if ad_id is a number you should add the numericality parameter in the validates statement, see below:
class AdsAttrValue < ActiveRecord::Base
validates :ad_id, numericality: true
#validate if add_att_value has the permitted values
validate :myCustomValidation
def myCustomValidation
#your logic of validation goes here
#you can access here all the fields from this object recently created
if attr_val == something
#do something
end
end
end
See that validations from rails have an s at the end (validates), and your own written validations do not have (validate).
This validations are executed when creating the object before storing in database in order to see if it complies the validations and not stored it it does not comply. You can add errors in your own validation to let the user know what gone wrong. Go further with this reading of validations in ruby on rails

How to make the association in model so I can get all places of user_places's id in rails console?

I have 2 tables for example:
user_places
----------------
| id | place_id|
----------------
| 1 | 1 |
----------------
| 1 | 5 |
----------------
| 1 | 6 |
----------------
| 2 | 8 |
And a places table
--------------------------------------------
| id | title | description | image_url |
--------------------------------------------
| 1 | 1 | description1 | image1 |
--------------------------------------------
| 2 | 5 | description2 | image2 |
--------------------------------------------
| 3 | 6 | description3 | image3 |
--------------------------------------------
| ...| ... | description4 | image4 |
How to make the association in both models so I can get all places of user_places's id = 1 in rails console?
You'll want to look up foreign_keys, especially pertaining to Rails.
Rails is basically a way for you to interact with a relational database. As such, if you know how to correctly structure a relational DB, you'll be able to better understand Rails' ActiveRecord associations, and how they fit into applications.
--
How to make the association in both models so I can get all places of user_places's id = 1
You'd do this:
#app/models/user.rb
class User < ActiveRecord::Base
has_and_belongs_to_many :places
end
#app/models/places.rb
class Place < ActiveRecord::Base
has_and_belongs_to_many :users
end
This means you have to change your user_places table to the following:
#places_users
#user_id | place_id
This will allow you to call:
$ #user = User.find "1"
$ #user.places #-> 1,5,6
--
The other answer recommended a has_many :through relationship. Whilst this allows you to add other data into your join model, it means you have to include a user_places model for no real reason (at this stage).
I would recommend using has_and_belongs_to_many for the moment. This limits you to only having references in your join table, but makes the entire association much simpler:
The big caveat here is that you'll need to change your user_places table to have an alphabetical nameflow (places_users), and make sure you only have the two foreign_keys as columns: user_id | place_id

ruby on rails - how to take only take one row

Restaurant Load (1.5ms) SELECT * FROM "restaurants" INNER JOIN
"restaurant_branches" ON "restaurant_branches"."restaurant_id" =
"restaurants"."restaurant_id"
+----------+---------+---------+---------+----------+---------+----------+---------+---------+---------+---------+---------+---------+---------+---------+-------+
| resta... | res_... | res_... | crea... | updat... | user_id | resta... | addr...
| addr... | addr... | addr... | addr... | addr... | numb... | numb... | email |
+----------+---------+---------+---------+----------+---------+----------+---------+---------+---------+---------+---------+---------+---------+---------+-------+
| 27 | DOGG... | WE S... | 2014... | 2014-... | 4 | 28 | 405 ...
| | CHICAGO | IL | 60666 | USA | | | |
| 27 | DOGG... | WE S... | 2014... | 2014-... | 4 | 29 | 111 ...
| | CHICAGO | IL | 60661 | USA | | | |
+----------+---------+---------+---------+----------+---------+----------+---------+---------+---------+---------+---------+---------+---------+---------+-------+
As you can see, I have two records for record 27. This is from a joined
table between restaurants and restaurant_branches. How would I approach
this in a view so that when I select a record on my index.html.erb file
when it gets routed to the show.html.erb file it'll only take one row of
that record and only show me one branch instead of 2?
Thank you for any help.
The two records are different, so keep them separate and list both. It's difficult to say which fields are different from the question. Based on the query, I'm assuming they are restaurant_branches fields that are different.
If it's the restaurants that you want to show/edit then use just Restaurant.all however you want to limit. If however you want to edit the restaurant_branches then introduce a RestaurantBranchesController and have a link for the branches separate.
Something like (in erb):
<%= restaurant.id %>
<% restaurant.restaurant_branches.each do |rb| %>
<%= link_to 'Some branch', rb %><br />
<% end -%>
Then the link_to(rb) should link you to RestaurantBranchesController#show action for the particular restaurant_branch.
Collection
Further to what #vee was suggesting, it seems to me that you're calling a collection of data from ActiveRecord. A collection basically means you're going to receive a multitude of objects back, rather than just one record
I'd imagine you have your models set up as follows:
#app/models/restaurant.rb
Class Restaurant < ActiveRecord::Base
has_many :branches, class_name: "RestaurantBranch"
end
#app/models/restaurant_branch.rb
Class RestaurantBranch < ActiveRecord::Base
belongs_to :restaurant
end
This will give you the ability to call the following:
#restaurant = Restaurant.find params[:id]
#restaurant.branches #-> returns the collection
--
Limit
The way to fix this will depend on what you're trying to show.
Typically, you can use something like limit to retrieve a single record, like so:
#restaurant.branches.limit(1)
Like most things in life, this will be much simpler to resolve if you define what you want to limit the results for - what's the purpose?

How to delete record from only associated table with has_and_belongs_to_many relation ship

I have two model hotel and theme and both has has_and_belongs_to_many relationship
and third table name is hotels_themes, So I want to delete record only from third tables hotels_themes.
hotels_themes;
+----------+----------+
| hotel_id | theme_id |
+----------+----------+
| 8 | 4 |
| 9 | 5 |
| 11 | 2 |
| 11 | 4 |
| 11 | 6 |
| 12 | 2 |
| 12 | 5 |
+----------+----------+
I want to delete record which match hotel_id and theme_id.
Like sql query delete from hotels_themes where hotel_id=9 and theme_id=5
Use the method delete added to HABTM collections:
hotel = Hotel.find(hotel_id)
theme = Theme.find(theme_id)
hotel.themes.delete(theme)
You just need to empty out the association on either model instance depending on what you are trying to remove. For example:
hotel.themes = []
# or
theme.hotels = []

Resources