RoR: открепление записи со ссылкой для изменения логического атрибута на false?

#ruby-on-rails #model-view-controller #ruby-on-rails-5

#ruby-on-rails #модель-представление-контроллер #ruby-on-rails-5

Вопрос:

Я ищу ссылку, позволяющую пользователю отменить закрепленный твит.

Мое мнение

  <% if tweet.pin? %>
        <%= link_to '<i class="fas fa-thumbtack"></i> Unpin'.html_safe, pin_tweet_path(tweet), :method => 
        :put, class: "dropdown-item" %>
    <% else %>
        <%= link_to '<i class="fas fa-thumbtack"></i> Pin to your profile'.html_safe, pin_tweet_path(tweet), 
        :method => :put, class: "dropdown-item" %>
    <% end %>
 

Моя модель (tweet.rb)

     belongs_to :user, optional: true

    scope :pin,  -> { where(pin:true) }
     scope :no_pin, -> (id) { where.not(id: id) if id }
    
     after_save :ensure_only_one_pinned_tweet
    
   private
     def ensure_only_one_pinned_tweet
       user.tweets.pin.no_pin(id).update_all(pin: false) if pin?
     end
 

Мой метод контроллера

 def pin
    @tweet = Tweet.find(params[:id])
    if @tweet.update(pin: true)
      redirect_to user_path(current_user.id)
    else
      @tweet.update(pin: false)
      redirect_to user_path(current_user.id)
    end
  end
 

Мой маршрут

 resources :tweets do
    member do
      put :pin
    end
  end
 

Эта настройка позволяет автоматически заменять каждый pin-код при выборе пользователем другого pin-кода, тем самым одновременно используя только один pin-код. Это работает нормально.

Но я хочу включить возможность для пользователя также отменить закрепление и, следовательно, не иметь выводов.

Какой самый простой способ сделать это? ty

Обновить

Обновление с помощью pin-контроллера

 resources :tweets do
...
    resources :pins
...
end
 

Маршруты

 tweet_pins GET    /tweets/:tweet_id/pins(.:format)                                                         pins#index
                                      POST   /tweets/:tweet_id/pins(.:format)                                                         pins#create
                        new_tweet_pin GET    /tweets/:tweet_id/pins/new(.:format)                                                     pins#new
                       edit_tweet_pin GET    /tweets/:tweet_id/pins/:id/edit(.:format)                                                pins#edit
                            tweet_pin GET    /tweets/:tweet_id/pins/:id(.:format)                                                     pins#show
                                      PATCH  /tweets/:tweet_id/pins/:id(.:format)                                                     pins#update
                                      PUT    /tweets/:tweet_id/pins/:id(.:format)                                                     pins#update
                                      DELETE /tweets/:tweet_id/pins/:id(.:format)                                                     pins#destroy
 

Вид

 <% if tweet.pin? %>
  <%= link_to '<i class="fas fa-thumbtack"></i> Unpin'.html_safe, tweet_pin_path(tweet), method: :patch, class: "dropdown-item" %>
<% else %>
  <%= link_to '<i class="fas fa-thumbtack"></i> Pin to your profile'.html_safe, tweet_pin_path(tweet), method: :patch, class: "dropdown-item" %>
<% end %>
 

Ошибка

 No route matches {:action=>"show", :controller=>"pins", :tweet_id=>#<Tweet id: 18, user_id: 2, content: "Pin test", created_at: "2020-11-23 15:15:03", updated_at: "2020-11-23 15:22:39", retweet_id: nil, pin: nil>}, missing required keys: [:id]
 

Ответ №1:

Одна из моих самых любимых статей в блоге — как DHH организует свои контроллеры Rails. Итак, имея это в виду, мне интересно, почему у вас есть pins действие. Я думаю, ваша жизнь была бы намного проще, если бы у вас был просто TweetsController#update или, может быть, даже Tweet::PinsController если у вас больше функциональности. С помощью функции обновления вы можете просто принять значение pins атрибута вместо того, чтобы устанавливать для него значение true.

 class PinsController
  def update
    @tweet = Tweet.find(params[:id])
    if @tweet.update(pin: params[:pin])
      flash[:success] = 'Pinned tweet!'
      redirect_to user_path(current_user.id)
    else
      flash[:error] = 'Ups, something went wrong here!'
      redirect_to user_path(current_user.id)
    end
  end
end

 

Затем просто обновите свои маршруты и представления, чтобы использовать update маршрут, и все должно быть в порядке. Обновление кода модели не требуется.

Комментарии:

1. привет, Тай, как будет выглядеть маршрутизация для нового контроллера контактов? Я использую ресурсы: контакты в моей маршрутизации и исправление на мой взгляд, но он продолжает пытаться перейти к действию show.

2. Пожалуйста, взгляните на руководство по маршрутизации Rails guides.rubyonrails.org/routing.html . Я почти уверен, что эту ошибку можно легко исправить, проведя некоторое исследование того, как на самом деле работает маршрутизация 😉