Rails 3: проблема понимания MVC этого запроса - PullRequest
0 голосов
/ 08 июля 2011

Если вы знакомы с Railscasts, я следовал за полем токена # 258, чтобы изначально настроить его, где Райан руководит книгами авторов has_many через авторские права, я использую сообщения художников has_many через ремесленные мастерства. (и сообщения принадлежат пользователям) http://asciicasts.com/episodes/258-token-fields

Итак, другими словами:

У меня есть сообщения, создаваемые пользователем с полями title и artist, форма post содержит виртуальный атрибут для поля Artist под названием artist_tokens, с этим виртуальным атрибутом связан метод setter Artist_tokens = (ids).

Это метод, который вызывает у меня проблемы с пониманием. Метод делает 2 вещи. Он берет идентификаторы, введенные в форму сообщения и вызывает Artist.create! используя идентификаторы как: имя. Затем он вызывает .id на любом оставленном объекте Artist. Это итоговый идентификатор artist_id, который используется для создания ассоциации ремесленников.

1) Что происходит, когда я вызываю Artist.create (: name => $ 1) внутри модели поста?

2) Затем этот запрос переходит к методу create внутри контроллера Artist?

Я понимаю, что обычный запрос post отправляется в метод postscontroller # create и затем записывается в базу данных, а затем перенаправляется на любой путь в методе создания, например post_path, поэтому он попадает в postscontroller # show и затем вид. Правильно?

3) Какова последовательность запросов от контроллера к модели, чтобы посмотреть, что я делаю, когда я вызываю Artist.create! из метода artist_tokens = (ID) внутри модели поста?

# app/models/user.rb

class User < ActiveRecord::Base
  has_many :posts, :dependent => :destroy
  has_many :artists, :through => :posts
  attr_accessible :email, :password, :password_confirmation, 
                  :remember_me, :name, :avatar, :username, :bio
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  mount_uploader :avatar, AvatarUploader       

end



# app/models/post.rb

class Post < ActiveRecord::Base

  belongs_to :user
  has_many :artisanships
  has_many :artists, :through => :artisanships
  attr_accessible :title, artist_tokens
  attr_reader :artist_tokens

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

end

# all/models/artist.rb

class Artist < ActiveRecord::Base

  has_many :artisanships
  has_many :users, :through => :posts
  has_many :posts, :through => :artisanships
  attr_accessible :name
end


# app/models/artisanship.rb

class Artisanships < ActiveRecord::Base

  belongs_to :post
  belongs_to :artist
  has_one :user, :through => :post
  attr_accessible :post_id, :artist_id
end

# app/views/shared/_post_form.html.erb

<%= 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 %>    # html 5 data attribute for prepopulate
    </div>
  <div class="actions">
    <%= f.submit "Submit" %>
  </div>
<% end %>


# app/controllers/pages_controller.rb

class PagesController < ApplicationController

  def home
    @title = "Home"
    @featured_posts = Post.featured.limit(10)
    if user_signed_in?
      @user = current_user
      @post = current_user.posts.build
      @feed_items = current_user.feed.paginate(:per_page => "10", :page => params[:page])
    else
     #render :layout => 'special_layout' 
    end
  end

# app/controllers/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
end

# app/controller/artists_controller.rb

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

  def show
    @artist = Artist.find(params[:id])
  end

  def new
    @artist = Artist.new
  end

  def create
    @artist = Artist.build(params[:artist])
    if @artist.save
      redirect_to @artist, :notice => "Successfully created artist."
    else
      render :action => 'new'
    end
  end

  def edit
    @artist = Artist.find(params[:id])
  end

  def update
    @artist = Artist.find(params[:id])
    if @artist.update_attributes(params[:artist])
      redirect_to @artist, :notice  => "Successfully updated artist."
    else
      render :action => 'edit'
    end
  end

  def destroy
    @artist = Artist.find(params[:id])
    @artist.destroy
    redirect_to authors_url, :notice => "Successfully destroyed artist."
  end

end

1 Ответ

1 голос
/ 08 июля 2011

1) Artist - это класс, который наследуется от ActiveRecord. Когда вы вызываете метод класса create, он принимает различные поля, настроенные вами в базе данных, и пытается сохранить запись. Возвращает полученный объект. Обратите внимание, что если у вас есть проверки в вашей модели, и объект не проходит их, создание не сохранит запись.

2) Нет, контроллер вообще не трогается. Контроллер используется для того, чтобы указать, как приложение должно реагировать на URL-запрос. Artist # create отвечает на запрос POST к URL / художникам. В действии create вы просто указываете, что вы хотите сделать, когда поступит этот запрос. В этом случае вы хотите сохранить опубликованные данные в качестве исполнителя в базу данных.

3) Вид ответил на это в # 2, но вот как это работает. Когда URL попадает на сервер, Rails проверяет ваши маршруты и выясняет, куда он должен идти. Затем он вызывает код внутри вашего контроллера. Если какие-либо модели вызываются, он выполнит код там. При условии, что вы не выполняете перенаправление или что-то в этом роде, он затем выполняет соответствующее представление, имея в наличии все переменные экземпляра, объявленные внутри действия.

Надеюсь, это прояснит для вас. :)

...