FriendlyId suggest - ruby-on-rails-3

I want to use FriendlyId to achieve this localhost3000/users/edu/profile but I do not know how to do it!
I have these models User and UserProfile
class User < ActiveRecord::Base
has_one :user_profile, :dependent => :destroy
extend FriendlyId
friendly_id :name, :use => :slugged
end
class UserProfile < ActiveRecord::Base
attr_accessible :user_id, :name, :surname, :nickname
belongs_to :user
end
How do I load in name of User the name of UserProfile? and
How do you update name of User when the name of UserProfile changes?
For the first I used
class User < ActiveRecord::Base
...
def name
if user_profile
"#{user_profile.name}"
end
end
But I can't make it change when I update or create a new Profile in UserProfile.
Using Ruby 1.9.3 and Rails 3.2.13.

If I understood it correctly, your problem is about sharing data between models, not about FriendlyId.
It seems delegate is your best bet here. It's a method in ActiveSupport that allows one model to expose another model's methods as their own.
class User < ActiveRecord::Base
delegate :name, :name=, :to => :user_profile
end
Reference: http://api.rubyonrails.org/classes/Module.html#method-i-delegate
The reason to delegate both :name and :name= is that the former method allows you to read from that attribute (getter), while the latter allows you to write to it (setter).
Before making these changes you'll want to run a migration to remove the name field from the users table in the database, since from now on you'll be using the data in the other model.
rails g migration remove_name_from_users name:string

Related

How can I introduce a has_one_belongs_to_one association in Rails model?

My Rails application has users and tasks created by users. Users can also create a task and assign another user to it. I am not quite sure how to build associations here.
I know since a task is created by a user, I can have an association as below,
class User
has_many :tasks, dependent: :destroy, foreign_key: :user_id
end
class Task
belongs_to :user
end
I also want to add an association for creator in the Task model but I am not sure how to do it since a creator will also be an instance of the User class and I already have a belongs_to association with User
I tried to add an association for creator in Task model in the following way but it didn't work.
has_one :user, foreign_key: :creator_id, class_name: "User"
Since you've already defined the belongs_to :user method, the method #task.user is already taken by that association. You can't use the same name for a different method, so you'll have to use a different name for that association.
The association name doesn't have to be the same as the model. You can name the creator association something else, like "creator":
has_one :creator, foreign_key: 'creator_id', class_name: "User"
Since the task has a foreign key for the creator, you should be able to use belongs_to for both associations:
class Task
belongs_to :user
belongs_to :creator, foreign_key: 'creator_id', class_name: 'User'
end
Here's a discussion about the difference between has_one and belongs_to: What's the difference between belongs_to and has_one?
Either way way you can do:
#task.user # the User who is assigned the task
#task.creator # the User who created the task

Handling relationship with ActiveRecord

I have two models to make a relationship between them, where I need to access stores of a radar and the radars of a store. A radar could monitoring zero or many stores. A store could belong to zero, one or many radars.
I would like to have something like this:
store = Store.first
store.radars #all radars of the store location
And the opposite too:
radar = Radar.first
radar.stores #all stores of the radar location
My classes:
class Store < ActiveRecord::Base
attr_accessible :title, :description, :user, :store_group, :city,
:neighborhood, :sublocality, :post_code, :route,
:street_number, :latitude, :longitude
end
class Radar < ActiveRecord::Base
attr_accessible :name, :radius, :latitude, :longitude, :user
end
How can I create a migration to handle this?
What you are looking for is a has_and_belongs_to_many association between radars and stores. The question you need to ask your self is will there ever be any attributes on the the joining between the two models? If so you might considering using an explicit join model, that will hold those attributes. In that case you would be looking at a has_many :through association.
see http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association for information on the HABTM association.
your migration for a HABTM would be something like this.
class CreateRadarStores < ActiveRecord::Migration
create_table :radars_stores, :id => false do |t|
t.belongs_to :radar
t.belongs_to :store
end
end
The order of the table name is important, since by default rails creates it in alphabetical order of the models.
Your models would need to be updated to include the HABTM
class Store < ActiveRecord::Base
has_and_belongs_to_many :radars
....
end
class Radar < ActiveRecord::Base
has_and_belongs_to_many :stores
....
end
or if using a has many :through look here http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
Building that join model would be up to you depending upon attributes reuqired.

Counter cache doesn't get updated - not sure why

I have a stores application on github. I'm trying to implement counter_cache for two models, 1. Divisions model and 2. Products model. For some reason I'm not sure of the counter cache(divisions_count) doesn't get incremented automatically for the Company model whenever I create a new Division and similarly the products_count doesn't get incremented for the Divisions model when I add a new product to the division.
I'm on rails 3.2.11 and on ruby 1.9.3-p327
My application is only at POC level.
PFB the model structure wrt Company, Division and Product:-
company.rb
class Company < ActiveRecord::Base
attr_accessible :contact_no, :email_id, :fax_no, :name, :website, :divisions_count
has_many :divisions #just added divisions_count to attr_accessible not sure if it helps
has_many :products, :through => :divisions
end
division.rb
class Division < ActiveRecord::Base
attr_accessible :company_id, :name, :products_count
#just added products_count to attr_accessible not sure if it helps
belongs_to :companies, :counter_cache => true
has_many :products
end
product.rb
class Product < ActiveRecord::Base
attr_accessible :division_id, :model, :name, :price
belongs_to :divisions, :counter_cache => true
end
In case you want to refer to the migrations that I've created for the counter cache implementation , you may find them here.
I believe the problem is that you’ve set up belongs_to incorrectly by using the plural name. Switching to singular solves the problem, i.e.
# pseudo diff:
- belongs_to :companies, :counter_cache => true
+ belongs_to :company, :counter_cache => true
- belongs_to :divisions, :counter_cache => true
+ belongs_to :division, :counter_cache => true
When editing models/associations I found it helpful to think of an actual instance. So, it makes sense that the “Windows”-division belongs to “Microsoft”-company, but it makes no sense that it belongs to “Microsoft”-companies. Or just remember belongs_to is always singular and has_many is always plural.
If you need your divisions to belong to multiple companies, you need to use a different association called “has and belongs to many” or HABTM for short (see [1]).
[1] http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association

Implementing a has_many :through

I am thinking of creating the following models using 'has_many :through':
class Contract < AR::Base
has_many :clientlines
has_many :codelines
has_many :clients, :through => :clientlines
has_many :codes, :through => :codelines
end
class clientlines < AR::Base
belongs_to :contract
belongs_to :client
end
class Client < AR::Base
has_many :clientlines
has_many :contracts, :through => :clientlines
end
class codeline < AR::Base
belongs_to :contract
belongs_to :code
units_alloc -------**I would like to add this attribute after this intermediate
end has been created?
class Code < AR::Base
has_many :codelines
has_many :contracts, :through => :codelines
end
Do I first create the models with 'rails generate model Contract authnum:string, client_id:integer, st_date:date, end_date:date' for example.
Then fill in all of the associations before the migrations?.
Also, my understanding is that all of the join tables are created automatically by rails when using the has_many :through association. When does that happen?
Lastly, as indicated by the **, can I have this attribute in codelines, and do I create a 'rails generate migration add_units_alloc_to_codelines units_alloc:number' in order to add this attribute to the join table? I was also wondering how I declare the number to be too two decimal places?
If you have the time and inclination could you please comment on my proposed design for my database?
Thanks.
by using has_many :through you use a third model that makes the connection between the other two, so rails doesn't automatically build that model, you build it yourself and reference the foreign keys for the other two models.
don't name your models at their plural, always singular. if you can't name them at singular, you're doing it wrong
The order in which you create your models shouldn't matter too much (rails generates some migrations which you can easily modify later)
That units_alloc attribute, just add it to the model when you create it, simple as that!
for 2 decimals use something like t.decimal :amount, :precision => 6, :scale => 2 in your migration (that example gives you 6 digits and 2 decimals)
Read the Rails Guides, it will really help you get out a lot of trouble

How to give foreign key a name in RoR 3?

How can I give foreign key a name in RoR?
I use following command to give foreign key:
rails generate scaffold Table2 id:integer Table1:references
This command adds foreign key of Table1 in Table2 but with default name that is Table1_id. So how can I give custom name to it for example my_table_f_key instead of Table1_id.
I'm using Ruby 1.9.2 and Rails 3.0.3.
Edit:-
In my project.rb model:
belongs_to :own, :class_name => User
In my user.rb model:
has_many :owned_projects, :class_name => Project, :foreign_key => :owner
how I created my project model
rails generate scaffold Project name:string owner:integer
Now when I access user_id from Project like
project.owner.userid it throws exception.
Based on your responses in the comments, this is one way of implementing what you want to do:
Assuming two models in your app (Users and Questions), and two different relationships:
User asks many Questions, Question belongs_to Asker
User edits many Questions, Question belongs_to Editor
You could implement this structure in the following way:
rails generate scaffold Question asker_id:integer editor_id:integer
Specifying id:integer in your generate command is redundant, as Rails will generate that column for you automatically. It's also conventional to name your foreign keys in terms of the relationship (ie, asker_id).
Then, inside each of your models:
class Question < ActiveRecord::Base
belongs_to :asker, :class_name => User
belongs_to :editor, :class_name => User
end
class User < ActiveRecord::Base
has_many :asked_questions, :class_name => Question, :foreign_key => :asker_id
has_many :edited_questions, :class_name => Question, :foreign_key => :editor_id
end
That way, you can use them together like this:
#question.asker # => User
#question.editor # => User
#user.asked_questions # => [Question, Question, Question]
#user.edited_questions # => [Question, Question]
Hope this helps.
Adding to #Dan's answer, pass the class name as String.
DEPRECATION WARNING: Passing a class to the class_name is deprecated and will raise an ArgumentError in Rails 5.2. It eagerloads more classes than necessary and potentially creates circular dependencies. Please pass the class name as a string
class Question < ActiveRecord::Base
belongs_to :asker, :class_name => User
belongs_to :editor, :class_name => User
end
class User < ActiveRecord::Base
has_many :asked_questions, :class_name => 'Question', :foreign_key => :asker_id
has_many :edited_questions, :class_name => 'Question', :foreign_key => :editor_id
end