Rails : How does "new" action called "create" action? - ruby-on-rails

I am following this tutorial http://guides.rubyonrails.org/v3.2.13/getting_started.html to build my rails app in version 3.2.13 . If you go to the section 6.9 you will find controller and view for creating new posts . Here I do not get how #post variable is passed from new action to create action and where is create function called ? Also , I faced the same problem while working on edit and update actions . Please guide me through this .

It's not passed to create action, it's instantiated again with params you pass from the form displayed with new action.
create action is called with POST request to the path specified in config/routes.rb, leading to specific controller and action.

#post is not passed from new to create the params hash is passed into the create method #post is then set using the new method of the model not the controller. create calls new and then save and returns the object. new returns the object without saving and then save returns the validity of the object. That is why the create method in the controller calls new and then has a conditional statement for save. It is basically saying initialize this object then if it is a valid object do one thing if it is not do another. The create action is not called because of this check.
#this will return true if valid or false if invalid
Post.new(params[:post]).save
#this will always return the Post object which conditionally is true in Ruby
Post.create(params[:post])
#To use the create in a conditional statement it would be
Post.create(params[:post]).valid? || Post.create(param[:post]).save
The last line is unnecessarily redundant and thus why the example uses new followed by save.
create method for a Model is more succinct but probably best to use when you know the object is valid.
Hope this gives you a better understanding but if you are still confused please let me know and I will try to explain further.

Related

At what point does a controller class instantiate a controller object in a Rails web app?

Learning Rails, the point at which a controller gets instantiated is unclear to me whereas, the point at which a model gets instantiated is somewhat recognizable as for example, when a user enters data in a from and clicks the submit button is sort of a trigger that leads to a creation of an object model.
Done some research and I'm visualizing in my head that when a HTTP request is sent via the browser, the routing to a controller becomes the trigger to instantiate a certain controller object from a controller class.
Is this somewhat correct?
When the HTTP request enters your application server (puma, webrick, etc), the request passes through a stack of middleware (defined in rails gem), which converts the HTTP request into an instance of ActionDispatch::Request class which is used to determine the correct route to dispatch to appropriate controller class in your rails app based on the route definitions defined in config/routes.rb.
The generated request object is then dispatched to the corresponding controller and action method which instantiates the Controller class and invokes an action method on it's instance with an argument of params object (instance of ActionController::Parameters).
This is just a general overview of how Controllers are instantiated. The request object passes through a series of middleware classes and modules before a request object is generated.
Here's a good article if you want to read it in detail.
As we define the routes in routes.rb, than the control goes to that controller action at that time the controller get's initiated to work
It is more related to object oriented programming, The object is always instantiated when you call new on class
2.0.0-p648 :001 > Class.new
=> #<Class:0x007fee8e99d9a8>
2.0.0-p648 :002 >
Here the object is instantiated, and similarly in rails when you call any action lets say
def new
#article = Article.new
end
new object gets initiated, when you click on save, you are actually calling create action, and pass the current object.
def create
#article = Article.create(article_params)
#article.save
end
here .create method filled object with article_params and .save method saves object in database.

Getting params from URL in model's create method

Is there a way to get the params from URL in the create method?
My URL for the "new" view is:
/model_name/new?other_model_id=100
I would like to be able to alter the model with ID 100 when I create a new model. I've tried calling params[:other_model_id] in my "create" method, which returned nil and I tried setting the following variable in my "new" method:
#other_model = Model.find(params[:other_model_id])
I have a field called "other_versions" in my model, which is an array of model IDs. When I create a new model I want to add the new model's ID to the array of model IDs in the old model.
Why don't you use the after_createfilter (http://guides.rubyonrails.org/active_record_callbacks.html) and just add the "other_model" id on an hidden field on your create/edit form?
Please make sure, if you are using Rails >4, to add that parameter on your strong parameters (http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html) otherwise it will always be empty when you check on params.

How to call to another controller passing all the params in Grails (to update the associated table in the same form)

I'm working with the domain class Alojamiento, and its generated controller and views. The next code works:
I have included in the form of a view another form:
<g:render template="../caracteristicas/form" bean="${params.caracteristicasInstance}" />
Now, the edit action of the controller has:
def alojamientoInstance = Alojamiento.get(id)
def caracteristicasInstance = alojamientoInstance.caracteristicas
[caracteristicasInstance: caracteristicasInstance,
And to the update action of the controller:
def caracteristicasInstance = Caracteristicas.get(id)
caracteristicasInstance.properties = params
caracteristicasInstance.save(flush: true)
As I said, the above code works, but it is not protected against errors, so I'm trying to use the update action of CaracteristicasController (I'm following this approach: http://stuff4j.blogspot.com.es/2011/04/calling-controller-method-from-another.html). The next code does NOT work, but I think it explain itself what I'm trying:
CaracteristicasController caracteristicasController = new CaracteristicasController()
CaracteristicasController.properties = params
CaracteristicasController.params.doNotRedirect = 'true' // See: http://stuff4j.blogspot.com.es/2011/04/calling-controller-method-from-another.html
CaracteristicasController.update()
By the way, the error of Grails is: "Cannot set read-only property: properties"
UPDATE 1
I think I didn't explain something well. I have in _form.gsp 3 embedded _form.gsp (I said in my question 1 to simplify). So when I edit _form.gsp, the others must be updated too. I want to call the update action of the "child" controllers to update the forms, but not move to them. I want to keep being in the "parent" controller so when everything updates, the show.gsp of the "parent" will appear. Do I explain it better now?
Why don't you redirect or chain with all need params?

Can't understand what this text is saying

I am following a tutorial and got to this point: http://rubysource.com/building-your-first-rails-application-views-and-controllers/
rails generate controller urls new
The reason we only passed in the new action (instead of new, create,
and show) is because Rails automatically generates a dummy view for
each action included in the generator call. In this case, we only want
a dummy view for the new action, so we exclude the others.
So why we only need to create the controller for new? Can someone plase explain it in a little more details?
The command is used to create the UrlsController with only one method: new.
This command will also automatically create a view file for you in:
app/views/urls/new.html.erb
Had you supplied more arguments like:
rails generate controller urls new create show
You would have gotten:
app/views/urls/new.html.erb
app/views/urls/create.html.erb
app/views/urls/show.html.erb
Since the tutorial only needs the new view it was unnecessary to create the additional views, hence those additional arguments were not added to the generate command.
Later in the tutorial you manually add the create and show methods, but you never add views for those methods (since those methods will not be needing specific views files in this application).
So: what you did was create the controller UrlsController with one method new, and the corresponding view for that method. The rest of the methods you will code in manually later in the tutorial so there was no need to auto-generate anything else (create or show).
This will only create the new action in the controller and should skip the other ones.
EDIT:
It will generate a controller called UrlsController in app/controllers and in that controller there will only be one method called action which corresponds to a route or url called urls/new

Performing AJAX calls on the "new" controller

In my rails app, I want to have a sortable list as part of an object creation. The best practice suggested in Railscast adds the acts_as_list plugin and then initiates AJAX calls to update item position. However, AJAX calls won't work on an unsaved model, which is the situation with new.
One solution would be to save the model immediately on new and redirect to edit. This would have a nice side effect of persisting any change so the user could resume work should he be interrupted.
However, this solution adds the unwanted complexity of saving an invalid model, compromising rails' validation processes. Is there any better way to allow AJAX + validations without going into too much work?
Your new action has the same access to parameters that any other action has. You could pass parameters for the unsaved object back to the new action and an object re-initialized with attributes set could be returned back to the view. For instance:
controller:
class WidgetsController < ApplicationController
def new
#widget = params.has_key?(:widget) ? Widget.new(params[:widget]) : Widget.new
end
..
end
Then in your view you'd have to send params to the new action via a link or a form post.
you can temporary store unsaved object in a 'session'.
like (this code must be in controller)
my_model = MyModel.new(params[:my_model])
session[:my_model_tmp] = my_model

Resources