Rails - Create multiple resources from javascript/coffeescript datas - ruby-on-rails

Suppose I've a model : Thing
class Thing < ActiveRecord::Base
attr_accessible :name, :url
In my coffeescript, I've a function generating an array of JSON objects, eg:
[{"url":"https://www.example.com/1","name":"1"},
{"url":"https://www.example.com/2","name":"2"},
{"url":"https://www.example.com/3","name":"3"}]
That function is called when the user click on a button in the index page of Thing.
What I want is create multiple Thing resources based on the JSON objects generated by the coffeescript function.
What is the best way to do it?
I'm considering using Ajax to redirect to the create action of Thing but not sure this is the best way.
Thanks

Yes, AJAX is the way to go. What you'd do is submit these objects to the controller where you'd make your Thing models.
If you're submitting all of those objects and once and want them all created in one shot you could do that in the create action or you could do that in a create_all action. I like the idea of a create_all action because it's letting us know it's not a simple create action where people have learned to assume it just makes 1 of an object. This is a personal preference though.

Related

Rails 4 new form defaults from params

I am using form_for in the _form.html.erb view in order to create my form for both the edit and new actions, as per a standard scaffold.
I have a model Owner which has_many pets.
I would like to put an html link on my views/owners/show.html.erb to create a new pet for said owner. This link will point to the new action of pets_controller.rb which when accessed will render the view in pets/new.html.erb
What I want to happen is for the the owner_id to be passed with the link in the url to the new action of pets_controller.rb and then be used as the default for a collection_select in pets/new.html.erb
So I have a link to create a new pet but because that link was on a specific owner page, I want the form to create a new pet to have that owner already set, so the user does not have to select from the list.
This has to be done without changing the behaviour of the edit action/view in pets.
I know that I can pass GET arguments then access them in the controller via params, then create variables in the action which are passed to the view. I can then manually check for a default and set it in the view. I do not need assistance in coding if this is the only solution.
Is there is a better way to do this? A format with which I can pass the params such that the view will just pick them up? Without manually editing my controllers and views?
While my personal inclination would be to do as you said and pass a parameter in the link helper and then access the params array in the pets view, you may find that this is the perfect opportunity to explore Nested Resources. Essentially, you could declare owners/:owner_id/pets/:pet_id route with:
resources :owners do
resources :pets
end
You could then link to this route, and reference :owner_id without having to append the query string to the URI (making somewhat cleaner for reuse).
This is likely more work for you, but also potentially more extensible (and certainly more inline with the Rails way of doing things).
REVISION
Added the following regarding link helpers to the comments, but wanted to reflect it in the answer as well.
To show a pet should be:
<%= link_to owner_pet_path( owner_variable, pet_variable) %>
To view pets' index index should be:
<%= link_to owner_pet_path( owner_variable ) %>
The answer given to this question is fantastic.
As #ConnorCMcKee suggests it would be wise to consider nesting your routes. However, if you are a beginner as myself I found that it helped my learning to simply nest my second controller into the first (i.e. nest PetsController into OwnersController) as a first step. Then afterwards I would continue with the routes.
The method would be something like:
1./ In owners/index.html.erb:
Links to PetsController index action
The key to make this work is to send the :owner_id in your link parameters. Then that Pets index action will have access to that :owner_id and know which :owner_id called it.
2./ In PetsController you would then be able to find that Owner using that id, like so:
params[:owner_id]
Then your actions can start to take advantage of knowing what Owner called them. Remember though that all your redirects inside your PetsController need to preserve params[:owner_id]. That is because once you are inside that nested structure you have to maintain it and stay inside it and always know which :owner_id you are working with.

Rails. How to put few controllers on one page

I am working on Todo app now and I have troubles. After sign in, I am on persons profile(first controller), on it I have button for new project(projects controller-2d controller) and after pressing it, appears button for new tasks(task controller-3d controller). How I can put all of this 3 controller's views on one page. Here an example of what I mean(approximately):http://todo.kzotov.ru/
You can put anything you want in the view. You could eager load the projects and tasks and put it all on the profile page. You also don't have to map controllers and views to models, so if the PersonsController or whatever is not what you're looking for, maybe do something more specific like ProfilesController and host all this functionality there.
MVC
You'll be best reading up on the MVC programming pattern -
The bottom line is that if you send a request to your application, it will only hit one controller#action. Your multiple "controllers" should not be something to consider - you should only look at the single controller action you're accessing at that specific time.
To be more specific about this, let me detail how it all works...
OOP
Ruby (on top of which Rails is a framework), is object orientated.
This is not just a fancy phrase - it's a real pattern of programming, which allows you to focus the flow of your application around the data / objects you want to create. The objects in Rails are derived from your Models - collating & organizing the respective data for your controllers
In order to understand how Rails works - you need to appreciate that everything you do is based on objects. Your routes, actions & data all work together to provide the end-user experience we know from Rails. How that happens is down to you.
Specifically, you want to look what what you're accessing
You don't want to load multiple controllers - you want to build several models and show those. This gives you the ability to show the HTML elements / files you want:
Recommendation
I would make sure you can put all your activity on your single view, which will then mean you have to determine your controller's data in order to provide you with the data you need to show:
#app/controllers/profiles_controller.rb
class ProfilesController < ApplicationController
def index
#your index
end
end
#app/views/profile/index.html.erb
<%= link_to "task", task_path %>
What you'll probably want to do is create a separate route / method to give them the ability to pull back ajax data when the initial button was clicked. I can detail this if you need it, but what I've given you should be ample food for thought

Rails MVC: Should a form collection_select know which collection records it should render?

I'm a little stuck here with a conceptual issue. Assume following [abstracted] setup for Post, Tag, and User:
Post belongs_to Tag
Tag has_many Posts
User has_many Tags,
has_many Posts
A user can only tag a post with one of his associated tags.
In the new post form view, I now have following options for selecting a tag:
f.collection_select :tag_id, current_user.tags, ...
f.collection_select :tag_id, #tags, and in the controller's new action:
#tags = current_user.tags
Question: What is the conceptually correct option?
From an MVC perspective, I definitely tend towards using the second option. It does not seem right that the view knows that the tags it should render in the collection_select are associated to a user (even more specific, the current user!).
However, in the official api documentation for collection_select and some other tutorials around the web I see something like this:
collection_select(:post, :author_id, Author.all, ...)
which clearly favors the first option. On the pro-site of this approach, I do not need to redefine the #tags in the create action of the controller in case the post's save action fails and I want to render the new action again.
Thank you for your suggestions in advance.
There's nothing wrong with your first option. For starters, it's simpler (one less line of code). Setting an extra instance variable within your controller doesn't really gain you anything.
A good way of thinking about the controller is that it should only be doing things like setting variables when they are based directly upon input that only the controller receives (such as parameters in the URL, query string, or data from a POSTed form).
The view in this case isn't deciding how to determine the current user - that's still coming from your controller (although probably inherited from the top-level ApplicationController or something like Devise?), all it's doing is deciding that it's the tags of the current user which should be be selectable within the drop-down view.
Does that help?

custom action for a nested resource without adding to routes

This is probably really simple but I have a nested resource lets say:
map. resources :book, :has_many => :pages
I write an action called "turn" that increases page.count by 1. How do I call this action using a link_to? Thanks a lot in advance.
It's hard to tell where your page.count comes in. In Railish, you would find pages.count (note the 's'). Further, count (and also size) is a read-only attribute on arrays and hashes et.al. provided by ruby that returns the number of elements. You don't set count.
Next, I'm not sure where your turn action is supposed to live, on the Book or the Page? And what is supposed to happen after it does what it does? Finally, a route is what makes an action an action -- without it, it's just a function.
For a moment, we'll assume you are trying to store the number of times a Page in a Book has been visited. It would be a better idea to have an instance variable called reads or times_viewed etc. in your Page model. Assuming your Book model is using restful routing, in Book's show action, you create an instance variable of the Page model being viewed and increment its reads attribute before rendering the view.
If you are trying to make a link sort of how 'Like' works in Facebook, meaning you want to update a record in a table without sending the user to a different page, you'll need to use link_to_remote* and some javascript. In that case, I'd just refer you to the Railscasts on that subject.
*I think as of Rails 3, link_to_remote became just link_to with :remote => true.

Making a single create form using Single Table Inheritance in Rails

I'm using STI in Rails, and I've got a Vehicle object, that has many different types of subclasses, like Car, Truck, etc. It's for a simple app, so STI works fine in this case, but I'm having trouble creating a single form where any type of Vehicle record can be created.
Using the following routing:
resources :vehicles
resources :cars, :controller => 'vehicles'
resources :trucks, :controller => 'vehicles'
I can have /cars and /trucks routing set up, and both pointing to the same form. However, since the form is pointing to the vehicles controller, and generating a Vehicle object for the form, it has no way to know that the /cars url should create a Car object.
I'm trying to get a routing system set up where /cars would point to a form that would intrinsically know to make a object for the form using either Car.new or even Report.new(:type => "Car"). I thought about working a routing system like /vehicles/:subclass, and somehow using params[:subclass] in the controller, but I also can't figure out how to do that sort of routing and still avoid other routing errors caused by Rails' STI magic.
I could always parse the URL to get the value, but that seems like an unsafe and hacky way to go about it.
I'm curious if anyone has any advice or experience on the Rails way to do this. Thanks!
Since you want to use the same form for all vehicles, then I'm assuming all the fields are the same except for the object type. Then why not have a combo box in the form to allow the user select what type of object the user want to create?
You can then handle the proper object persistent in the create action in the controller.

Resources