开发者

Rails 3: Problem understanding the MVC of this request

If you're familiar with railscasts I followed #258 token field to initially set this up, where ryan bates books has_many authors through authorships, I'm using posts has_many artists through artisanships. (and posts belong_to users) http://asciicasts.com/episodes/258-token-fields

So in other words:

I have user's creating posts with the fields title and artist, the post form contains a virtual attribute for the artist field called artist_tokens, this virtual attribute has an associated setter method called artist_tokens=(ids).

This is the method that is giving me problems understanding. The method does 2 things. It takes the ids entered into the post form and calls Artist.create! using the ids as the :name. Then it calls .id on whatever artist object is left. That is the resulting artist_id which is used to create the artisanship association.

1) What is happening when I call Artist.create(:name => $1) from inside the post model?

2) Does that request then go to the create method inside the artist controller?

I understand a normal post request would go to the postscontroller#create method and then write to the database and then redirect to whatever path is in the in the create method such as post_path, so it hits the postscontroller#show and then to the view. Correct?

3) What is the sequen开发者_运维百科ce of request from controller to model to view that I'm doing when I call Artist.create! from the artist_tokens=(ids) method inside the post model?

# 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) Artist is a class that inherits from ActiveRecord. When you call the class method create, what it does is accept the various fields you have setup in the database, and attempts to save the record. It returns the resulting object. Note that if you have validations in your model, and the object does not pass them, the create will not save the record.

2) No, the controller is not touched at all. The controller is used for a place to specify how you want the application to react to a url request. The artist#create responds to a POST request to the url /artists. In the create action, you simple specify what you want to do when that request comes in. In this case, you wish to save the posted data as an artist into the database.

3) Kind of answered this in #2, but here's how it works. When a url hits the server, Rails checks your routes and figures out where its supposed to go. It then calls the code inside your controller. If any models are invoked, it will execute the code there. Provided you do not do a redirect or something, it will then execute the appropriate view, having available all instance variables declared inside the action.

I hope this clears it up for you. :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜