Rails form_for only change controller - ruby-on-rails

I would like to tell form_for to use a different controller without affecting the action.
I know how to change the URL like
form_for #car, url: { controller: 'admin/cars' }
but this will also change the action.
Is there any way I can use a different controller with form_for without affecting the automatic choosing of the action?

You can also specify the action like this and could pass the controller name as a variable:
form_for #car, url: { controller: #controller_name, action: "your_action" }

You can also select action in routes, maybe this is helpful for you;
form_for #car, url: { cars_path }
in your routes file ;
post '/cars', to: 'cars#action_whatever_you_want'

Related

Link_to target '_blank' combined with controller action

I have the code:
= link_to image_tag(image_info), 'web-site', :target=>'blank'
which works great to open the site in a new tab BUT -
The image is an advertisement that I am hosting and I want to also record the fact that the image was clicked and time and other details.
Is there a way to combine the link_to, target '_blank' with a call to a controller action?
You can achieve that with Javascript and to record the click time you need to define an action which will save the time and other details.
= link_to image_tag(image_info), 'web-site', class: 'save-time'
JS:
$('.save-time').on('click', function(e){
e.preventDefault();
var linkUrl = $(this).attr('href');
$.ajax({
url: '',
type: 'POST'
success: function(response){
if(response){
window.open(linkUrl, '_blank');
}
}
})
});
Hope that helps!
One non-Javascript way of going about this would be to create a controller action that:
Does whatever tracking you want to do
redirects to your external website.
Then set your link up so that it calls your controller action directly.
As a very simple example, that would benefit from a bit more sophistication:
Route
# config/routes.rb
# [...]
get 'tracking/:url_id', to: 'tracking#redirection', as: 'track_redirection'
Controller
# app/controllers/tracking_controller.rb
class TrackingController
def redirection
url = {
1 => 'google.com',
2 => 'bbc.com'
}[params[:url_id]]
TrackingClass.new(url, current_user).track
redirect_to url
end
end
View
= link_to image_tag(image_info), track_redirection_path(1), target: 'blank'
This will create an internal link to /tracking/1 which your controller will then redirect to the correct url.
You can link to the controller method path
link_to "controller/method", target: 'blank', method: :post do
image_tag image_path("whatsapp-icon.svg")
end
Routes
# config/routes.rb
resources :controller do
post "method" => "controller#method"
end

Render another new form

I have two routes with new action for the same resource: individual_trainings :
new_backend_trainer_ind_training GET /backend/people/:id/trainers/:trainer_id/individual_trainings/new(.:format) backend/individual_trainings#new
new_backend_individual_training GET /backend/individual_trainings/new(.:format) backend/individual_trainings#new
How to specify what type of new should be rendered? If I use render :new, always redirect to second route. I don't want to use redirect_to, because I cannot handle errors for form. Any idea how to do this (I need render :new in create action). Maybe another new and create action?
Update:
I think there is a problem with simple_form in new_backend_trainer_ind_training :
= simple_form_for([:backend, #individual_training]) do |f|
it generates wrong url. Is it right?
If you want to do it this way (two routes for the same action) then you can pass path to simple_form:
= simple_form_for(#individual_training, url: new_backend_trainer_ind_training_path) do |f|
However, this is a bad approach to use different routes leading to the same action. If this is a different behavior, then you should create another controller with it's new/create action.

Building a form for a like button in a polymorphic relationship in Rails

I'm trying to build a form for a like button. This like model is polymorphic to different types of Models (comments / posts / etc.) and belongs to a certain user.
When this user is viewing a blog item for instance, I want to show a like button below the post. I've set-up my routes in a way that the like routes are always nested inside the polymorphic object for which they are destined:
So for posts for instance:
#routes.rb
resources :posts do
resources :likes, only: [:create, :destroy]
end
So a post link would look like /posts/:post_id/likes/ (method: Post)
In the controller I create a new Like object, assign it to a user and save it. This works perfectly.
The problem is when I'm trying to create delete form. I really have no clue how to create that, I know the link should be /posts/:post_id/like/:id (method: Delete), but configuring it this way results in an error.
I think the form could also be refactored, but I have no clue on how making forms for these kind of 'complex' relationships.
#shared/_like_button.html.haml
- if not #post.is_liked_by current_user
= form_for(#post.likes.build, url: post_likes_path(#post)) do |f|
= f.submit
- else
= form_for(#post.likes.find_by(user_id: current_user.id), url: post_like_path(#post), html: {method: :delete}) do |f|
= f.submit
I think the main problem is that post_like_path(#post) doesn't get rendered correctly because I'm not aware of the :id of the like. So I keep getting an ActionController::UrlGenerationError in PostsController#show error when trying to build the link.
This should work:
= form_for([#post, #post.likes.find_by(user_id: current_user.id)], html: {method: :delete}) do |f|
url: post_like_path(#post) in your code expects a second argument (the like object). That's what throws the error.
But you don't need it actualy if you put the nested resources as an array in the first argument of the form_for helper.
If the record passed to form_for is a resource, i.e. it corresponds to
a set of RESTful routes, e.g. defined using the resources method in
config/routes.rb. In this case Rails will simply infer the appropriate
URL from the record itself.
(source: http://apidock.com/rails/ActionView/Helpers/FormHelper/form_for)
You can pass an array of resources if your resource is nested within another resource.
Now... You probably want to re-use this code for your other polymorphic models as well. You can do this by passing #post, or #comment to your partial like this:
= render :partial => 'like_button', locals: {likable: #post}
and refactor your partial like this:
= form_for([likable, likable.likes.find_by(user_id: current_user.id)], html: { method: :delete}) do |form|
There's no need to use an actual form, you could do it with a link_to. Here's an example with basic text link (to make sure it's working)
- if not #post.is_liked_by current_user
= link_to 'Like', post_like_path(#post), method: :post
- else
= link_to 'Delete', post_like_path([#post, #post.likes.find_by(user_id: current_user.id)]), method: :delete
Then you use an image/button as the link itself.
- if not #post.is_liked_by current_user
= link_to post_like_path(#post), method: :post do
# some html image/button
- else
= link_to post_like_path([#post, #post.likes.find_by(user_id: current_user.id)]), method: :delete do
# some html image/button
Updated this code with help from the accepted answer so anyone looking in future can use link_to.

Manage Single Rails form to other controller with create and update action

i'm new of rails. I use rails 3.0.5 .
I have an EMPLOYEE resource, but I would like to manage it with another extern controller (emp_profile_controller).
This extern controller (emp_profile_controller) manages some actions (index, new_employee, create_employee, edit_employee, update_employee ecc.. ) .
My routes for this controller are :
controller :emp_profile do
get 'emp_profile' => :index
get 'emp_edit_profile' => :edit_employee
put 'emp_edit_profile' => :update_employee
get 'new_employee' => :new_employee
post 'new_employee' => :create_employee
get 'emp_list' => :emp_list
end
How can i use one form to handle both Create and Update actions in this controller ?
I tried with :
form_for(#employee, :url => { :controller => "emp_profile"}) do |f|
but it doesn't work.
If i manage only one action at time (create OR update), url_for works, for example :
form_for(#employee, :url => { :controller => "emp_profile", :action => "update_employee" }
but how can i handle both actions with one form ?
Thanks for your availability and I apologize if I asked a stupid question.
EDIT
For now, i solved checking if object exist in the form file, if exist i set a variable with the UPDATE action path, else, i set a variable with the CREATE action path. So in the form_for statement i use url_for with the above variable.
<% if #employee.new_record?
action = "create_employee"
method = "post"
else
action = "update_employee"
method = "put"
end
%>
form_for(#employee, :url => { :controller => "emp_profile", :action => action }, :method => method
I don't think it is the best way but it works and i can use only one form file.
As your model name and controller name are different, you can add this line to your routes
resources :employees,:controller=>"emp_profile",:path=>"emp_profile"
Change the method names of create_employee,update_employee to create and update respectively.
And change your form_for as given below
<%= form_for #employee do |f| %>
....
<% end %>
First of all, if you want to update something, this object should exist.
How do plan to find it out, I don't know (cause there different ways, depends on background).
There are 2 ways of solving this issue.
You can just check if object exist in view file, and if exists, renfer form for update, else for create.
Other way is to do it in controller.
For example:
def create
#employee=Employee.find_by_name('Jack Black') #for example
if #employee!=nil
render :action=> 'update'
else
#employee=Employee.new(:employee)
#employee.save
end
as i understand you want to execute two different actions on the same controller using a form submitting, this is not possible, you can only execute one action using a form submitting,
because the form is reaching to an action controller that action is suppose to render some view at the end of it's execution code, if it was possible to use to actions on form submitting how rails will know which view to render??? (that's why it's not possible).
if you want to do some more code execution at the controller, the right way to it is to call a method with some code in it that you want to execute, that method should be in the model,
because it is a good practice to write all massive chunks of code in the model and leave the controller as light from code as possible :-)
hope this helps.

Rails : How to create more than one form with a submit button, doing different functionality?

I want to create more than one form with a submit button, with each submit button having a different action/functionalities to perform.
How to achieve this? For now all the submit buttons takes the create controller method as its action function. How to override this ?. Can I give name to each submit button and redirect each button's action to different method in its controller file?
How to do it ? I'm using rail 3.0.1.
If you're using the form_for helper method, I believe it uses the new_record? method on whatever object you're passing it to determine the proper action it should point to. For example:
<%= form_for #page do |f| %>
If #page.new_record? evaluates to true, the form will POST to the create method on the PagesController. However, if it evaluates to false, it will POST to the update method on the PagesController.
You can override the URL the form POSTs to by doing something like:
<%= form_for #page, :url => { :action => "my_action" } do |f| %>
That will allow you to send the form data to a custom action. You don't have to change anything related to the submit buttons.
Hope that helps!

Resources