简体   繁体   中英

Setting up Rails Controller for the through in has_many through relationship

I am creating a rails web app with a many-to-many through model. The application is to allow users to populate their dashboard with a number of pre-defined "widgets". So I have a table of users (created and managed by devise) and a table of widgets. All good. So to manage the through bit, I have a table of "subscriptons". Here are my models:

class Subscription < ActiveRecord::Base
  belongs_to :user
  belongs_to :widget
  validates_uniqueness_of :user_id, scope: :widget_id
end

class User < ActiveRecord::Base
  has_many :subscriptions
  has_many :widgets, through: :subscriptions
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
end

class Widget < ActiveRecord::Base
  has_many :subscriptions
  has_many :users, through: :subscriptions
end

However, I don't really understand how to create the subscriptions. I would ideally like the create form to just have a selector to choose from all available widgets and then user the current user:id but I am not sure how this would work, here is my controller:

  def new
    @subscription = Subscription.new
  end

  def create
    @user = current_user
    @subscription = @user.subscriptions.build(subscription_params)

    respond_to do |format|
      if @subscription.save
        format.html { redirect_to @subscription, notice: 'subscription was successfully created.' }
        format.json { render :show, status: :created, location: @subscription }
      else
        format.html { render :new }
        format.json { render json: @subscription.errors, status: :unprocessable_entity }
      end
    end
  end

I would really appreciate a nudge in the right direction, as I can't understand how this is done from the official docs and haven't found any good tutorials relating to this.

Assuming you don't have any other attributes on subscriptions you can use the widget_ids= method that your has_many creates on user

Controller

class UserSubscriptionsController
  def edit
    @user = current_user
  end

  def update
    @user = current_user
    if @user.update(user_subscription_params)
      redirect_to @user, notice: "Subscriptions updated"
    else
      render :edit
    end
  end

  private

  def user_subscription_params
    params.require(:user).permit(widget_ids: [])
  end
end

View

<%= form_for @user, url: user_subscription_path, method: :patch do |f| %>
  <%= f.collection_check_boxes :widget_ids, Widget.all, :id, :name %>
  <%= f.submit %>
<% end %>

The routes in my example would have

resource :user_subscription, only: [:edit, :update]

But obviously you can amend based on what you want your routes to be. Rails will automatically create the subscriptions when updating the user.

You could instead just use the collection_check_boxes when editing a user normally if you wanted. There is also collection_select

Docs

You can save data like this using subscription form.

  = form_for @subscription do |f|
   = f.select :widget_id, options_from_collection_for_select(Widget.all, "id", "title"), {}, {:class => "form-control select" }
   = f.hidden_field :user_id, :value => current_user.id
   #other subscription fields
   = f.submit

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM