title: How van I allow index only for same profile?
body: <p>My app is a weight loss app. It uses Devise for user authentication. </p>
  
  <p>A user <code>has_one :profile</code> (the profile table holds the <code>user_id</code> as foreign key) that stores data like prename, surname etc. and is created automatically when a user signs up. A profile <code>has_many :weights</code> (users of the app should weigh themselves regularly and store their new weight in this table). So far so good. </p>
  
  <p>I have the following problem:
  If a logged in user goes to the index page of the weight controller he sees only his own weights. However, if this user now changes the profile_id in the URL bar he can also see the weights of that other profile (although it is not "his" profile). Additionally, he can now create a new weight, which then holds the other profile_id (which is obviously not his own).</p>
  
  <p>What I managed to do is to generally restrict users to edit or destroy weights which do not hold their own profile_id (through <code>before_action :require_same_weight_profile</code> in my weights_controller.rb).</p>
  
  <p>My question now: how can I prevent this user (that has a certain profile) to do the stuff described above?</p>
  
  <p>I'm sure the answer is pretty simple (I started coding just a few months ago).</p>
  
  <blockquote>
    <p><strong>UPDATE</strong> In the meanwhile I found a solution. Unfortunately the suggested solutions in the comments did not work for me. What does
    work is the following:</p>
    
    <p><strong>My update in weights_controller.rb</strong></p>
  
  <pre><code>before_action :require_permission
  
  ...
  
  def require_permission
    if current_user != Profile.find(params[:profile_id]).user
      redirect_to root_path
    end
  end
  </code></pre>
  </blockquote>
  
  <p><strong>routes.rb</strong></p>
  
  <pre><code>Rails.application.routes.draw do
  
    devise_for :users
    resources :profiles, only: [:index, :show, :edit, :update] do
      resources :weights
  
    end
  </code></pre>
  
  <p><strong>profile.rb</strong></p>
  
  <pre><code>class Profile &lt; ActiveRecord::Base
    belongs_to :user
    belongs_to :pal
    has_many :weights, dependent: :destroy
    belongs_to :goal
  end
  </code></pre>
  
  <p><strong>weight.rb</strong></p>
  
  <pre><code>class Weight &lt; ActiveRecord::Base
    belongs_to :profile
  end
  </code></pre>
  
  <p><strong>weights_controller.rb</strong></p>
  
  <pre><code>class WeightsController &lt; ApplicationController
    before_action :set_profile
    before_action :load_profile
    before_action :set_weight, only: [:show, :edit, :update, :destroy]
    before_action :require_same_weight_profile, only: [:show, :edit, :update, :destroy]
  
  
    # GET /weights
    # GET /weights.json
    def index
      @weights = Profile.find(params[:profile_id]).weights
    end
  
    # GET /weights/1
    # GET /weights/1.json
    def show
    end
  
    # GET /weights/new
    def new
      @weight = Weight.new(:profile_id =&gt; params[:profile_id])
    end
  
    # GET /weights/1/edit
    def edit
    end
  
    # POST /weights
    # POST /weights.json
    def create
      @weight = Weight.new(weight_params)
  
      respond_to do |format|
        if @weight.save
          format.html { redirect_to profile_weights_path, notice: 'Weight was successfully created.' }
          format.json { render :show, status: :created, location: @weight }
        else
          format.html { render :new }
          format.json { render json: @weight.errors, status: :unprocessable_entity }
        end
      end
    end
  
    # PATCH/PUT /weights/1
    # PATCH/PUT /weights/1.json
    def update
      respond_to do |format|
        if @weight.update(weight_params)
          format.html { redirect_to profile_weights_path, notice: 'Weight was successfully updated.' }
          format.json { render :show, status: :ok, location: @weight }
        else
          format.html { render :edit }
          format.json { render json: @weight.errors, status: :unprocessable_entity }
        end
      end
    end
  
    # DELETE /weights/1
    # DELETE /weights/1.json
    def destroy
      @weight.destroy
      respond_to do |format|
        format.html { redirect_to profile_weights_path, notice: 'Weight was successfully destroyed.' }
        format.json { head :no_content }
      end
    end
  
    private
      # Use callbacks to share common setup or constraints between actions.
      def set_weight
        @weight = Weight.find(params[:id])
      end
  
      def set_profile
        @profile = Profile.find_by(user_id: params[:id])
      end
  
      def load_profile
        @profile = current_user.profile #|| current_user.build_profile
      end
  
      # Never trust parameters from the scary internet, only allow the white list through.
      def weight_params
        params.require(:weight).permit(:profile_id, :weight, :weight_day)
      end
  
      # This checks if the current user wants to deal with weights other than his own
      def require_same_weight_profile
        if @weight.profile_id != current_user.profile.id
          flash[:danger] = "You can only edit or delete your own weights"
          redirect_to profile_weights_path(current_user.profile)
        end
      end
  end
  </code></pre>
  
  <p><strong>profiles_controller.rb</strong></p>
  
  <pre><code>class ProfilesController &lt; ApplicationController
    before_action :set_profile, only: [:show, :edit, :update, :destroy]
    before_action :load_profile
  
  
    # GET /profiles
    # GET /profiles.json
    def index
      @profiles = Profile.all
    end
  
    # GET /profiles/1
    # GET /profiles/1.json
    def show
    end
  
    # GET /profiles/new
    def new
      @profile = Profile.new
    end
  
    # GET /profiles/1/edit
    def edit
    end
  
    # POST /profiles
    # POST /profiles.json
    def create
      @profile = Profile.new(profile_params)
      @profile.user = current_user
  
      respond_to do |format|
        if @profile.save
          format.html { redirect_to @profile, notice: 'Profile was successfully created.' }
          format.json { render :show, status: :created, location: @profile }
        else
          format.html { render :new }
          format.json { render json: @profile.errors, status: :unprocessable_entity }
        end
      end
    end
  
    # PATCH/PUT /profiles/1
    # PATCH/PUT /profiles/1.json
    def update
      respond_to do |format|
        if @profile.update(profile_params)
          format.html { redirect_to @profile, notice: 'Profile was successfully updated.' }
          format.json { render :show, status: :ok, location: @profile }
        else
          format.html { render :edit }
          format.json { render json: @profile.errors, status: :unprocessable_entity }
        end
      end
    end
  
    # DELETE /profiles/1
    # DELETE /profiles/1.json
    def destroy
      @profile.destroy
      respond_to do |format|
        format.html { redirect_to profiles_url, notice: 'Profile was successfully destroyed.' }
        format.json { head :no_content }
      end
    end
  
    private
      # Use callbacks to share common setup or constraints between actions.
      def set_profile
        @profile = Profile.find_by(user_id: params[:id])
      end
  
      def load_profile
        @profile = current_user.profile #|| current_user.build_profile
      end
  
      # Never trust parameters from the scary internet, only allow the white list through.
      def profile_params
        params.fetch(:profile, {}).permit(:prename, :surname, :birthdate, :gender, :size, :pal_id) 
      end
  
  end
  </code></pre>