30

I have two models, users and promotions. The idea is that a promotion can have many users, and a user can have many promotions.

class User < ActiveRecord::Base
  has_and_belongs_to_many :promotions
end

class Promotion < ActiveRecord::Base
  has_and_belongs_to_many :users
end

I also have a promotions_users table/model, with no id of its own. It references user_id and promotions_id

class PromotionsUsers < ActiveRecord::Base
end

So, how do I add a user to a promotion? I've tried something like this:

user = User.find(params[:id])
promotion = Promotion.find(params[:promo_id])
promo = user.promotions.new(promo)

This results in the following error:

NoMethodError: undefined method `stringify_keys!' for #<Promotion:0x10514d420>

If I try this line instead: promo= user.promotions.new(promo.id)

I get this error:

TypeError: can't dup Fixnum

I'm sure that there is a very easy solution to my problem, and I'm just not searching for the solution the right way.

idmean
  • 14,540
  • 9
  • 54
  • 83
Kevin Whitaker
  • 457
  • 1
  • 6
  • 12

5 Answers5

53
user = User.find(params[:id])
promotion = Promotion.find(params[:promo_id])
user.promotions << promotion

user.promotions is an array of the promotions tied to the user.

See the apidock for all the different functions you have available.

Tony Fontenot
  • 5,091
  • 1
  • 21
  • 19
11

You can do just

User.promotions = promotion #notice that this will delete any existing promotions

or

User.promotions << promotion

You can read about has_and_belongs_to_many relationship here.

Ju Nogueira
  • 8,435
  • 2
  • 29
  • 33
10

This is also useful

User.promotion.build(attr = {})

so, promotion object saves, when you save User object.

And this is

User.promotion.create(attr = {})

create promotion you not need to save it or User model

Mehmet Davut
  • 667
  • 10
  • 30
1

If you want to add a User to a Promotion using a prototypical PromotionsController CRUD setup and you're not using Rails form helpers, you can format the params as:

params = {id: 1, promotion: { id: 1, user_ids: [2] }}

This allows you to keep the controller slim, e.g., you don't have to add anything special to the update method.

class PromotionsController < ApplicationController

  def update
    promotion.update(promotion_params)

    # simplified error handling
    if promotion.errors.none?
      render json: {message: 'Success'}, status: :ok
    else
      render json: post.errors.full_messages, status: :bad_request
    end
  end

  private

  def promotions_params
    params.require(:promotion).permit!
  end

  def promotion
    @promotion ||= Promotion.find(params[:id])
  end
end

The result would be:

irb(main)> Promotion.find(1).users
=> #<ActiveRecord::Associations::CollectionProxy [#<User id: 2 ...>]>
Corinne
  • 11
  • 2
0

For all those in the current times, Rails does have built-in functions that are like simpler associations.

For building (i.e. Promotion.new), you can use

user.promotions.build(promotion_attributes)

For creating it's the same

user.promotions.create(promotion_attributes)

Just wanted to give a more familiar option. It's outline in the apidoc The other answers work as well.

marcus.salinas
  • 627
  • 4
  • 8