hershey
hershey

Reputation: 475

Rails 3 has_one / belongs_to relationship with model in subdirectory

I'm trying to create a simple relationship but with a model in a subdirectory under Rails 3.2

I have a User class and each user has an email subscription.. Because There will be other types of subscriptions (which also fill be added to users) I put them in a subdirectory . (My User happens to come from Devise but I suspect that won't matter.)

Here's the code

In model/user.rb

class User < ActiveRecord::Base
  has_one :email_sub

  before_create :build_email_subscription

  private

  def build_email_subscription
    Subscription::EmailSub.create(:is_subscribed => true, :user_id => self.id)
    true
  end
end

Note that I have also created a way to add a default subscription.

In model/subscriptions/email_sub.rb

class Subscriptions::EmailSub < ActiveRecord::Base
  belongs_to :user
end

In addition to the migrations to create the two classes I created the following migration for the relationship.

class AddSubscriptionToUser < ActiveRecord::Migration
  def change_table :subscriptions_email_sub do |t|
    t.referneces :users
  end
end

However, this doesn't seem to be working. It doesn't seem to be generating the user_id column.

Upvotes: 0

Views: 1025

Answers (2)

hershey
hershey

Reputation: 475

Looks like I got it to work. I'm sharing and annotating my result for others to learn.

In model/user.rb

class User < ActiveRecord::Base
  has_one :email_sub, :class_name => "Subscriptions::EmailSub"

  before_create :build_email_subscription

  private

  def build_email_subscription
    build_email_sub(:announcements => true, :notifications => true, :master => true)
    true
  end
end

I expressly include the class_name to find the model in the subdirectory. I used the build_<attribute> and passed in the parameters for three subscriptions (later to come in from a form but for now just setting defaults).

In model/subscriptions/email_sub.rb

class Subscriptions::EmailSub < ActiveRecord::Base
  attr_accessible :announcements, :daily_deals, :master
  belongs_to :user
end

(I left the attributes out above since they're not really relevant to the issue but I'll expressly include them here for beginning users.)

Instead of a new migration I modified the original migration for the EmailSubs model.

class CreateSubscriptionsEmailSubs < ActiveRecord::Migration
  def change
    create_table :subscriptions_email_subs do |t|
      t.boolean :master
      t.boolean :daily_deals
      t.boolean :announcements

      t.references :user    # I added this line to the generated migration
      t.timestamps
    end
  end
end

I added the t.references line. Note that I had it plural before and not singular (in a migration the table name needs to be plural, the field singular). t.references will know to look for the _id field given .

Hopefully this can help save some others some time.

Upvotes: 1

n_i_c_k
n_i_c_k

Reputation: 1534

I would redo the way you set up your models. I don't think it's good practice to try and edit relationship tables that rails creates automatically.

For your model user.rb

class User < ActiveRecord::Base
    has_many :subscriptions
    // Put whatever before_create logic here if that's still working correctly
end

Change subscription.rb to:

class Subscription < ActiveRecord::Base
    belongs_to :user
    belongs_to :subscription_type
end

Then make another model, subscription_type.rb

class SubscriptionType < ActiveRecord::Base
    has_many :subscriptions
end

This model would have 3 columns: id, subscription_id, and subscription_type_id, (and maybe a column subscription_type_name). Then make conventions like subscription_type_id of 1 is an email subscription, 2 is a magazine subscription or whatever, etc. Alternately, you could just add a subscription_type column in your subscription model.

For an easier time looking at what columns are in your models, use the annotate gem, here's a quick tutorial on how to use

Upvotes: 0

Related Questions