Это "правильный" способ обновить атрибут в приложении Rails? - PullRequest
0 голосов
/ 23 января 2012

Спасибо за поиск. Я изучаю рельсы и строю веб-приложение. Я пытаюсь быть «ОТЛИЧНЫМ» и думаю об этом. Поэтому я смотрю на свои данные как на ресурс. Предположим, у меня есть таблица под названием «Микросообщение» и столбец «Голоса», в котором подсчитано, сколько людей проголосовало за или против. У меня так работает:

По виду:

<td>
    <%= form_for feed_item do |f| %>
        <div><%= hidden_field_tag 'todo', 'upvote' %></div>
        <div class="action"><%= f.submit "Up" %></div>
    <% end %>
</td>
<td>
    <%= form_for feed_item do |f| %>
      <div><%= hidden_field_tag 'todo', 'downvote' %></div>
      <div class="action"><%= f.submit "Down" %></div>
    <% end %>
<td>

Когда пользователь нажимает кнопку, он вызывает метод «update» в контроллере. Затем в контроллере у меня это в обновлении:

  def update
    @todo = params[:todo]
    if @todo == "upvote"
      Micropost.find(params[:id]).increment!(:votes)
      flash[:success] = "Increase micropost vote"
      redirect_to root_path
    elsif @todo == "downvote"
      Micropost.find(params[:id]).decrement!(:votes)
      flash[:success] = "Decrease micropost vote"
      redirect_to root_path
    else
      redirect_to root_path
    end
  end

Я пропускаю скрытое поле, чтобы узнать, является ли нажатая кнопка «повышенным» или «понижающим». Итак, если я хочу изменить любой другой атрибут micropost, мне нужно иметь все больше и больше операторов if. Я не думаю, что я делаю это правильно. Какой способ обновления атрибутов или записи в БД?

Большое спасибо!

Ответы [ 4 ]

4 голосов
/ 23 января 2012

Я бы создал дополнительные действия upvote / downvote (или просто vote) и добавил бы их в качестве member ресурсов.REST не ограничивается CRUD, вы всегда можете добавить другие действия.Например, в Rails 2 это будет:

map.resources :my_resource, :member => {:upvote => :put}

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

3 голосов
/ 23 января 2012

Более RESTful переработкой является определение каждого из ваших действий в качестве отдельного маршрута, ПОЛУЧИТЕ, если вам нужно, в идеале POST, чтобы получить каждый из этих типов вызовов:

before_filter :load_micropost

def load_micropost
  @micropost = Micropost.find(params[:id])
end

def upvote
  @micropost.increment!(:votes)
  flash[:success] = "Increase micropost vote"
  redirect_to root_path
end

def downvote
  @micropost.decrement!(:votes)
  flash[:success] = "Decrease micropost vote"
  redirect_to root_path
end

Не забудьтесоздать методы типа load_micropost для обработки рутинной загрузки моделей.Нет никакого смысла в том, чтобы использовать несколько различных вызовов для вашего метода, которые в будущем могут потребовать корректировки.

Вы бы перенаправили их так:

map.resources :microposts,
  :member => {
    :upvote => :post,
    :downvote => :post
  }

Другая вещьВы можете рассмотреть вопрос о добавлении таблицы, в которой записывается, кто за что проголосовал, чтобы вы могли проводить аудит и корректировать при необходимости.Это позволяет легко отменить любое мошенническое действие без необходимости сбрасывать голоса оптом.

Вы также можете сделать простые ссылки, которые POST, если вы их попросите:

<%= link_to('Upvote', upvote_micropost_path(feed_item), :method => :post) %>

Это позаботитсяотрисовки любых необходимых элементов формы.

1 голос
/ 23 января 2012

Я бы сохранил голоса в отдельной модели Vote (micropost_id, user_id, positive, created_at), также добавил бы поле для микросообщений votes или что-то подобное, которое будет содержать (count_up_votes - count_down_votes).

После этого я создам новый ресурс votes под микросообщениями, поэтому у вас будет маршрут типа micropost_votes_path.

Если вы выберете этот дизайн, ваши пользователи смогут отменить свои голоса, и вы сможете предотвратить несколько голосов за пользователя.

0 голосов
/ 23 января 2012

Сначала добавьте виртуальный атрибут в вашу модель:

Class Micropost
  def change_vote(value)
    if value == 'upvote'
      votes += 1
    elseif value == 'downvote'
      votes -= 1
    end
  end
end

тогда в вашей форме убедитесь, что она использует помощники формы: (при условии, что feed_item является микросообщением)

<%= form_for feed_item do |f| %>
    <div><%= f.hidden_field 'change_vote', 'upvote' %></div>
    <div class="action"><%= f.submit "Up" %></div>
<% end %>

Это возвращает ресурс обратно в правильной форме для REST. Все, что нужно сделать контроллеру:

def update
  @mp = Micropost.find(params[:id])
  @mp.update_attributes(params[:micropost])
  if params[:micropost][:change_vote] == 'upvote' 
    flash[:success] = "Increase micropost vote"
  else
    flash[:success] = "Decrease micropost vote"
  end
  redirect_to root_url
end

Конечно, это еще не принимает во внимание валидации и тому подобное, но это НАИЛУЧШИЙ способ сделать это

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...