Rails拖放更改对象属性

时间:2014-07-03 04:09:44

标签: javascript jquery ruby-on-rails ruby ajax

我有两个型号;收藏和图像

收集模型

class Collection < ActiveRecord::Base
  has_many :images, dependent: :destroy
  accepts_nested_attributes_for :images
end

图片模型

class Image < ActiveRecord::Base
  belongs_to :collection    
  mount_uploader :file, ImageUploader   
end

一个集合has_many:images

在我的edit_collection视图中,我在网格视图中将所有图像显示为缩略图。目前我没有办法将图像发送到另一个集合。由于我不想强迫用户一次编辑一个图像,我认为这是一个使用拖放功能来更改图像所属集合的好机会。

我想在我的edit_collection页面上,它有图像缩略图网格,我会在旁边有一个集合列表。允许用户将图像缩略图拖动到集合上以更改图像的collection_id值。

因为我仍然很吵,我正在寻找一个教程来解决以这种方式更改属性,或者可能是一个宝石,或任何建议。到目前为止,我发现的所有材料似乎都专注于使用拖放来改变列表的层次结构。

有人有任何建议吗?

2 个答案:

答案 0 :(得分:1)

实现可拖动功能将需要某种类型的Javascript(我不知道任何抽象它的宝石),所以请确保您首先熟悉Javascript/Ajax is used in Rails的方式。

广义上最流行的解决方案可能是jQuery draggabledroppable的组合。您可以使用jquery-ui-rails gem(more instructions here)将这些内容添加到您的Rails应用中。您需要在app/assets/application.js文件中要求所需的模块:

//= require jquery
...
//= require jquery.ui.draggable
//= require jquery.ui.droppable
...
//= require_tree .

基本上你会想要在你的控制器上执行一个需要几个参数的动作(在这种情况下你想要移动它的图像idcollection_id),发现该图像并根据这些参数更改其集合,然后呈现Javascript或JSON响应以告知浏览器已进行(或不进行)更改 - 假设您希望保留在页面上。 e.g:

def change_collection
  @image = Image.find(params[:id])
  @image.collection_id = params[:collection_id]
  if @image.save
    render json: ..., status: ...
  else
    render json: ..., status: ...
  end
end

这只是一个给你一个想法的例子,你可能不希望因为安全原因而直接分配一个param。

您需要一条指向该操作的路线,例如:

resources :images do
  patch 'change_collection', on: :member 
end

然后你需要实现Javascript方面的东西。阅读API documentation for draggable和droppable以查看可用的方法/事件,并根据自己的喜好进行调整。你可能会做这样的事情:

$( ".html_class_representing_your_images" ).draggable();

$( ".html_class_representing_your_collections" ).droppable({
  drop: function() {
    Ajax request to the route we just made goes here
  }
});

您可以在其他地方找到有关如何使用jQuery发出Ajax请求的大量信息(包括如何使用成功/失败处理程序),但我只是告诉您,您需要找到一种方法来获取{ {1}}来自您的DOM元素,传统的方式是在视图中为它们提供ids属性(在我在顶部链接的指南中提到)。

将来,如果您添加更多这样的花哨功能,并且您的应用程序在前端开始变得非常复杂,以至于无法保持Javascript的有序性,那么您可能需要考虑像Backbone.js这样的前端框架而不是非常依赖DOM。

无论如何,我希望这至少可以让你开始。

答案 1 :(得分:0)

你可能想要使用ajax。

因此,当他们将图片拖到新的集合中时,在本地更新图片以获得该新ID,并且还向新的控制器操作发送ajax请求以处理此问题。您将传递旧图片ID和新集合以更新所需的属性。

由于你的标签,我认为你已经知道这是怎么回事,但是例如:

在前端,只要将图片拖入新的集合,就可以执行此类操作。

$.ajax({
    url: '/images/8',
    type: 'PUT',
    data: { new_collection: collection_id },
    success: function (response) {
        //do whatever you need, like maybe assigning the new id to the picture you have locally.
    },
    error: function (response) {
        // do whatever you'd do if it failed, like maybe ask them to try again. Since user is just dragging, ideally this would never happen, but perhaps they don't have internet connection. Again, at this point it becomes a matter of saying they can't do that without internet connection or maybe caching it locally, telling them you've cached it and that you'd go forward and do that when they have internet in the future. Tougher, but cooler and maybe nice to learn.
    }
});

在导轨方面,在routes.rb中,您有类似的内容:

resources :images,其中包括上述路线。

然后,在控制器ImagesController中,您将拥有以下内容。

def update
    @image = Image.find(params[:id])

    @image.assign_attributes(collection_id: params[:new_collection])

    if @image.save
        render json: @image, status: 200
    else
        render json: @image.errors.full_messages #not sure if right off the top of my head.
    end
end

基本上,这就是你要做的事情。