Rails:使用 jquery tokeninput (railscast #258) 创建新条目

发布于 2024-11-24 13:21:01 字数 4755 浏览 1 评论 0原文

我已经成功地添加了未包含在 Ryan Bates Railscast #258 http://railscasts.com/episodes/258-token-fields

换句话说,用户可以输入艺术家姓名,该姓名将使用 jquery tokinput 自动完成。但是,我希望自动完成结果仅显示由该单个用户创建的艺术家姓名。

这有道理吗?一个更好、更容易理解的例子是 collection.rb,用户在其中创建帖子并指定帖子所属的“集合”,但他们应该只能将帖子添加到他们自己创建的集合中。

这是以 Artist_tokens 作为虚拟属性的帖子表单:

<%= form_for @post, :validate => true, :html => {:multipart => true} do |f| %>
  <%= render 'shared/error_messages', :object => f.object %>
    <div class="field">
      <%= f.label :title, 'Title:' %><br /> 
      <%= f.text_field :title %><br />

      <%= f.label :artist_tokens, "Artists" %><br />
      <%= f.text_field :artist_tokens, "data-pre" => 
       @post.artists.map(&:attributes).to_json %>

    </div>
  <div class="actions">
    <%= f.submit "Submit" %>
  </div>
<% end %>

这通过在帖子表单上的artist_tokens 字段中输入的值来查找艺术家,我还添加了选项“Add {params[:q]}”来添加新条目。

class ArtistsController < ApplicationController

  def index
    @artists = Artist.where("name like ?", "%#{params[:q]}%")
    results = @artists.map(&:attributes)
    results << {:name => "Add: #{params[:q]}", :id => "CREATE_#{params[:q]}_END"}

    respond_to do |format|
      format.html
      format.json { render :json => results }
    end
  end

我添加了额外的代码来通过 id 解析“新”条目,然后用它们创建一个新的艺术家。然后再次分配artist_ids。

post.rb
 def artist_tokens=(ids)
    ids.gsub!(/CREATE_(.+?)_END/) do
      Artist.create!(:name => $1).id
    end
    self.artist_ids = ids.split(",")
  end

除了能够仅通过 current_user 的条目缩小 json 结果之外,一切都运行良好。我该怎么做呢?我需要在表中存储条目创建者的 user_id 吗?我该怎么做?

编辑:模型关联

# app/models/user.rb

class User < ActiveRecord::Base
  has_many :posts
  has_many :artists, :through => :posts

end



# app/models/post.rb

class Post < ActiveRecord::Base

  belongs_to :user
  has_many :artisanships
  has_many :artists, :through => :artisanships

end

# all/models/artist.rb

class Artist < ActiveRecord::Base

  has_many :artisanships
  has_many :users, :through => :artisanships
  has_many :posts, :through => :artisanships

end


# app/models/artisanship.rb

class Artisanships < ActiveRecord::Base

  belongs_to :post
  belongs_to :artist
  has_one :user, :through => :post

end

编辑:posts_controller.rb

class PostsController < ApplicationController

  before_filter :authenticate_user!, :only => [:create, :edit, :update, :destroy]
  before_filter :authorized_user, :only => [:destroy, :edit, :update]

  def create
    @user = current_user
    @post = current_user.posts.build(params[:post])
    if @post.save
      flash[:success] = "Post created!"
      redirect_to root_path
    else
       @feed_items = current_user.feed.paginate(:per_page => "10", :page => params[:page])
      render 'pages/home'
    end
  end

  def index
    @posts = Post.paginate(:page => params[:page])
  end

  def show
    @post = Post.find(params[:id])
  end

  def edit
    @post = Post.find(params[:id])
  end

  def update
      @post = Post.find(params[:id])
      respond_to do |format|
        if @post.update_attributes(params[:post])
          format.html { redirect_to(post_path(@post), :notice => 'Post was successfully updated.') }
        else
          format.html { render :action => "edit" }  
        end
      end
    end

  def destroy
    @post.destroy
    redirect_to root_path
  end

  def likers
     @title = "Likers"
     @post = Post.find(params[:id])
     @likers = @post.likers.paginate(:page => params[:page])
     render 'show_likers' 
   end

   def search
     if params[:q]
       query = params[:q]
       @search = Post.search do
         keywords query
       end
       @posts = @search.results
     end
   end


private
  def authorized_user
    @post = Post.find(params[:id])
    redirect_to root_path unless current_user?(@post.user)
  end

编辑:尝试使用alias_method_chain 首先设置帖子的user_id 属性。 (无法修复 NULL 数据库条目) 引用自:Rails 3:a​​lias_method_chain 仍在使用吗?

 def attributes_with_user_id_first=(attributes = {})
    # Make sure not to accidentally blank out the important_attribute when none is passed in
    if attributes.include?(:user_id)
      self.user_id = attributes.delete(:user_id)
    end

    self.attributes_without_user_id_first = attributes
  end
  alias_method_chain :attributes=, :user_id_first

I have successfully been able to implement the addition of new artist entries which was not included in Ryan Bates railscast #258 http://railscasts.com/episodes/258-token-fields

So in other words, a user can enter an artist name which will autocomplete using jquery tokinput. However, I'd like the autocomplete results to only display the artist names which were created by that individual user.

Does this make sense? An better and more understandable example would be for a collection.rb, where users create posts and specify a 'collection' for the post to belong to, but they should only be able to add posts to the collections which they created themselves.

This is the post form with artist_tokens as a virtual attribute:

<%= form_for @post, :validate => true, :html => {:multipart => true} do |f| %>
  <%= render 'shared/error_messages', :object => f.object %>
    <div class="field">
      <%= f.label :title, 'Title:' %><br /> 
      <%= f.text_field :title %><br />

      <%= f.label :artist_tokens, "Artists" %><br />
      <%= f.text_field :artist_tokens, "data-pre" => 
       @post.artists.map(&:attributes).to_json %>

    </div>
  <div class="actions">
    <%= f.submit "Submit" %>
  </div>
<% end %>

This finds the artist by the value entered into the artist_tokens field on the post form, and I also added the option "Add {params[:q]}" to add new entries.

class ArtistsController < ApplicationController

  def index
    @artists = Artist.where("name like ?", "%#{params[:q]}%")
    results = @artists.map(&:attributes)
    results << {:name => "Add: #{params[:q]}", :id => "CREATE_#{params[:q]}_END"}

    respond_to do |format|
      format.html
      format.json { render :json => results }
    end
  end

I added the additional code to parse the 'new' entries by id and then create a new artist with them. Then the artist_ids are assigned again.

post.rb
 def artist_tokens=(ids)
    ids.gsub!(/CREATE_(.+?)_END/) do
      Artist.create!(:name => $1).id
    end
    self.artist_ids = ids.split(",")
  end

Everything works great except the ability to narrow the json results by only the current_user's entries. How would I go about doing this? Do I need to store the user_id of the entries creator in the table? How can I do this?

EDIT: associations for models

# app/models/user.rb

class User < ActiveRecord::Base
  has_many :posts
  has_many :artists, :through => :posts

end



# app/models/post.rb

class Post < ActiveRecord::Base

  belongs_to :user
  has_many :artisanships
  has_many :artists, :through => :artisanships

end

# all/models/artist.rb

class Artist < ActiveRecord::Base

  has_many :artisanships
  has_many :users, :through => :artisanships
  has_many :posts, :through => :artisanships

end


# app/models/artisanship.rb

class Artisanships < ActiveRecord::Base

  belongs_to :post
  belongs_to :artist
  has_one :user, :through => :post

end

EDIT: posts_controller.rb

class PostsController < ApplicationController

  before_filter :authenticate_user!, :only => [:create, :edit, :update, :destroy]
  before_filter :authorized_user, :only => [:destroy, :edit, :update]

  def create
    @user = current_user
    @post = current_user.posts.build(params[:post])
    if @post.save
      flash[:success] = "Post created!"
      redirect_to root_path
    else
       @feed_items = current_user.feed.paginate(:per_page => "10", :page => params[:page])
      render 'pages/home'
    end
  end

  def index
    @posts = Post.paginate(:page => params[:page])
  end

  def show
    @post = Post.find(params[:id])
  end

  def edit
    @post = Post.find(params[:id])
  end

  def update
      @post = Post.find(params[:id])
      respond_to do |format|
        if @post.update_attributes(params[:post])
          format.html { redirect_to(post_path(@post), :notice => 'Post was successfully updated.') }
        else
          format.html { render :action => "edit" }  
        end
      end
    end

  def destroy
    @post.destroy
    redirect_to root_path
  end

  def likers
     @title = "Likers"
     @post = Post.find(params[:id])
     @likers = @post.likers.paginate(:page => params[:page])
     render 'show_likers' 
   end

   def search
     if params[:q]
       query = params[:q]
       @search = Post.search do
         keywords query
       end
       @posts = @search.results
     end
   end


private
  def authorized_user
    @post = Post.find(params[:id])
    redirect_to root_path unless current_user?(@post.user)
  end

Edit: Attempted alias_method_chain to set post's user_id attribute first. (didn't work to fix the NULL db entries)
referneced from: Rails 3: alias_method_chain still used?

 def attributes_with_user_id_first=(attributes = {})
    # Make sure not to accidentally blank out the important_attribute when none is passed in
    if attributes.include?(:user_id)
      self.user_id = attributes.delete(:user_id)
    end

    self.attributes_without_user_id_first = attributes
  end
  alias_method_chain :attributes=, :user_id_first

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

云淡月浅 2024-12-01 13:21:01

如果您不想修改模型中的任何内容,那么您可以这样做:

def index
  @artists = current_user.posts.join("artisianships").join("artists").
               where("artisianships.post_id = posts.id").
               where("artists.name like ?", "#{params[:q]}").
               select("artists.name as name, artists.id as id")
  results = @artists.map(&:attributes)
  results << {:name => "Add: #{params[:q]}", :id => "CREATE_#{params[:q]}_END"}

  respond_to do |format|
    format.html
    format.json { render :json => results }
  end
end

请注意,这里有很多连接,因此不推荐。

为了调试为什么 Artist.create!(:name => $1, :user_id => self.user_id) 不起作用,如果我们能看到更多代码,特别是 < code>action 创建一个 Post

更新:您是否尝试将 PostController#create 更改为以下内容,尽管我觉得当前的代码应该按原样工作,但

@post = current_user.posts.build
if @post.update_attributes(params[:post])
   # do something
else
   # do something else
end

我是不是 Rails 专业人士并且不理解 alias_method_chain 因此无法评论它为什么不起作用。

If you don't want to modify anything in your models, then you can do it like this:

def index
  @artists = current_user.posts.join("artisianships").join("artists").
               where("artisianships.post_id = posts.id").
               where("artists.name like ?", "#{params[:q]}").
               select("artists.name as name, artists.id as id")
  results = @artists.map(&:attributes)
  results << {:name => "Add: #{params[:q]}", :id => "CREATE_#{params[:q]}_END"}

  respond_to do |format|
    format.html
    format.json { render :json => results }
  end
end

Notice that there are a lot of joins going on here, so not recommended.

To debug why Artist.create!(:name => $1, :user_id => self.user_id) would not work, it would be great if we can see some more code, particularly the action to create a Post

UPDATE: Did you try changing PostController#create to following, although I feel curent code should work as it is,

@post = current_user.posts.build
if @post.update_attributes(params[:post])
   # do something
else
   # do something else
end

I am not a rails pro and don't understand the alias_method_chain so can't comment on why it didn't work.

泅渡 2024-12-01 13:21:01

如果您正在使用一些身份验证解决方案,例如 devise、clearance 或 authlogic,您可能已经有了 current_user 方法。
因此,向 Artist 模型添加一列 user_id:integer 并执行以下操作:

#User model
has_many :artists

#Artist model
belongs_to :user

#Artists controller
def index
    @artists = current_user.artists.where("name like ?", "%#{params[:q]}%") #this answers your question!
    ... blah blah
end

当然,不要忘记在创建艺术家时设置 user_id 列。

if you're using some authentication solution like devise, clearance or authlogic, you probably already have current_user method.
Therefore add a column user_id:integer to the Artist model and do the following:

#User model
has_many :artists

#Artist model
belongs_to :user

#Artists controller
def index
    @artists = current_user.artists.where("name like ?", "%#{params[:q]}%") #this answers your question!
    ... blah blah
end

And of course do not forget to set the user_id column when you create an artist.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文