Click pictures and update database row on rails - ruby-on-rails

I need to be able to click an image (out of a bunch of images) and update a profile table based on the image clicked.
List of images in my view:
<% #pages_selection.each do |pages_selection| %>
<img>
<%= link_to image_tag(pages_selection.page_picture, '#') %>
</img>
<% end %>
Then I've got a method in my controller, called save_new_scores_to_profile, that averages the data from the picture and updates the profile values.
How do I call my controller method when my link_to (the image) is clicked? Is there something like this available?
if link_to clicked
perform_controller_or_helper_method
end
Because the user needs to select multiple images, I want them to stay on the page after clicking the images (that's why I have the link directed to '#'. I also have a submit button at the end of the page if that helps.
I'm open to using something other than link_to.
EDIT:
Here's where I'm at now in routes
resources :preferences do
member do
get 'save_new_scores_to_profile'
get 'checked_average_with_profile'
end
end
and the view:
<% #pages_selection.each do |pages_selection| %>
<img>
<%= link_to image_tag(pages_selection.page_picture, :controller =>
:checked_average_with_profile, :action => :save_new_scores_to_profile, :image_id
=> pages_selection.id) %>
</img>
<% end %>
I have functions checked_average_with_profile and save_new_scores_to_profile in my controller that I know work (after testing with helper functions).

link_to image_tag(pages_selection.page_picture, :controller => :my_controller, :action => :save_new_scores_to_profile, :image_id => pages_selection.page_picture.id )
Insted of my_controller put the name of your controller.
With the :image_id you have passed a parameter that you can reference in your controller action with the params hash like: params[:image_id].
Do all your work in that controller action (or with additional calls of helper methods),
find the picture that has that image_id and make a redirect_to #picture_with_that_id

Related

Rails 5 custom method resource previous/next in controller or model?

I have a quiz application that uses acts_as_taggable and will_paginate to show one item at a time.
I created a model called MultipleChoiceQuestion (MCQ). Each MCQ has associated things with it, along with tags.
What I want to do is create a variety of different custom methods in the controller that will only collect questions that have certain tags attributed to the MCQ.
I want to then let the user see one question at a time with the custom method defined tags.
So, for example:
The controller:
def pharmas1
#sem1_pharma_mcq = MultipleChoiceQuestion.tagged_with(["pharmacology", "sem1"], :match_all => true).all.paginate(:page => params[:page], :per_page => 1)
end
The view
<% #sem1_pharma_mcq.each do |sem1_pharma_mcq| %>
<hr>
<%= sem1_pharma_mcq.question %> <Br>
<%= sem1_pharma_mcq.answer_one %>
<%= sem1_pharma_mcq.answer_two %>
<%= sem1_pharma_mcq.answer_three %>
<%= sem1_pharma_mcq.answer_four %>
<%= sem1_pharma_mcq.answer_correct %>
<%= sem1_pharma_mcq.answer_explanation %>
<%= sem1_pharma_mcq.tag_list %>
<hr>
<%= link_to "Next Question →", #sem1_pharma_mcq.next, :class => 'button next-question' %>
<%= will_paginate #sem1_pharma_mcq %>
<% end %>
The model:
acts_as_taggable
def next
MultipleChoiceQuestion.tagged_with(["sem1", "pharmacology"], :match_all => true).order(id: :asc).limit(1).first
end
def prev
MultipleChoiceQuestion.where("id < ?", id).order(id: :desc).limit(1).first
end
The routes.rb
resources :multiple_choice_questions, path: 'mcqs' do
get 'pharmas1', :on => :collection
end
I'm trying to accomplish two things:
Allow the user to view one question at a time with the rails "show" action/method, rather than using will_paginate to show one question at a time on the index.
I don't know how to go about this, and my functionality is working only through a custom gem? How can I show custom actions once per page in the show view template?
Allow the user to go previous/next on this show action/method but making sure that only questions of a certain tag are being applied.
The error here is: undefined method `next' for # when I try load the custom method named "pharmas1" -- which is defined in the multiple_choice_questions_controller.rb file

How to access a single, visible element from an array of objects being displayed by will_paginate?

I am working on a rails web app which manages students and courses. I have a courses controller which has the following index action:
def index
#courses = Course.paginate(:page => params[:page], :per_page => 1)
#courses.order(:startDate)
##thisCourse = Course.find(params[:page])
end
So pretty standard except for one thing - all the details of a single course are shown on one page and to show the details of the next course, you move to the next page of the pagination.
The problem is that in this index page showing the details of 1 course per pagination, I have a "Sign Up!" button which when pressed needs to create a a new record in the 'signups' db table which has the automated 'id' field and then the 'user_id' and the 'course_id' fields.
The 'user_id' is easy to find (current_user.id).
The 'course_id' is proving difficult. I imagine that pressing the Signup button should send the course_id to the signups_controller where a create function can do the work. But how can I get this exact course ID from the index page to the signups_controller's create action?
As you can see in the code I pasted from the courses_controller's index action,the '#thisCourse' variable has been commented out because I have found no way to define which course is currently being shown on the page.
The fields are rendered by the will_paginate Gem so I'm not sure how it's generating the fields but I was thinking that maybe I could create a named hidden field which includes the course_id and use that when the sign up button is pressed, however I'm not sure how to go about it.
Does anybody have any ideas?
Thanks!
Well, you can use show method (output one course) instead of index(output all courses) method, that will always get your course id through params.
Basically I changed my approach to the problem. I removed the button which was supposed to call the signups_controller and create the new record in the signups table. This button was replaced by adjusting the form_for helper so that it's submit button would send all the necessary data to the signups_controller (including the id value which was added to the form as a hidden field).
The form ended up looking like this:
<%= form_for course, :url => {:controller => "signups", :action => "create"}, :method => "post" do |f| %>
<%= hidden_field_tag :course_id, course.id %>
<%= f.label :"Course Title" %>
<%= f.text_field :courseTitle, class: 'form-control' %>
+ all fields included in the form....
<%= f.submit "Sign Up!", class: "btn btn-primary" %>
<% end %>
This parameter of form_for defines which controller and which action in that controller is the submission target:
:url => {:controller => "signups", :action => "create"}
and this parameter overwrites the default http action (default is PATCH but in this case I wanted to POST i.e. create a new entry in the signups table):
:method => "post"
I'm not sure if this is a very quick and dirty solution but technically it gets the necessary data to the correct destination controller.

Interpolated Ruby within a method call?

On my user model, I have a bunch of attributes like is_foos_admin and is_bars_admin that determine which kinds of records a user is allowed to edit.
I'd like to DRY out my edit links, which currently look like this:
<%= link_to 'Edit', edit_foo_path(foo), :class => 'edit' if current_user.is_foos_admin? %>
...
<%= link_to 'Edit', edit_bar_path(bar), :class => 'edit' if current_user.is_bars_admin? %>
I want to make a helper that lets me pass in a foo or bar and get back a link to edit it, like so:
<%= edit_link_for(foo) %>
The helper might look like this (which doesn't work):
def edit_link_for(thing)
if current_user.is_things_admin?
link_to 'Edit', edit_polymorphic_path(thing), :class => 'edit'
end
end
The model-agnostic edit_polymorphic_path method gets me halfway there, but it's the "is_things_admin" method that I don't know how to universalize. If I could use interpolated Ruby inside of a helper, I'd want to do something like
if current_user.is_#{thing.class.name.downcase.pluralize}_admin?
But of course that doesn't work. Any ideas?
Try using send:
if current_user.send("is_#{#model}_admin?")

Routing problem with calling a new method without an ID

I'm trying to put together a form_tag that edits several Shift objects. I have the form built properly, and it's passing on the correct parameters. I have verified that the parameters work with updating the objects correctly in the console. However, when I click the submit button, I get the error:
ActiveRecord::RecordNotFound in ShiftsController#update_individual
Couldn't find Shift without an ID
My route for the controller it is calling looks like this looks like this:
map.resources :shifts, :collection => { :update_individual => :put }
The method in ShiftsController is this:
def update_individual
Shift.update(params[:shifts].keys, params[:shifts].values)
flash[:notice] = "Schedule saved"
end
The relevant form parts are these:
<% form_tag( update_individual_shifts_path ) do %>
... (fields for...)
<%= submit_tag "Save" %>
<% end %>
Why is this not working? If I browse to the url: "http://localhost:3000/shifts/update_individual/5" (or any number that corresponds to an existing shift), I get the proper error about having no parameters set, but when I pass parameters without an ID of some sort, it errors out.
How do I make it stop looking for an ID at the end of the URL?
I think that you need to tell the form tag helper you want to use PUT instead of POST
<% form_tag( update_individual_shifts_path, :method => :put) do %>
... fields ....
<%= submit_tag "Save" %>
<% end %>
Amazingly, it turns out that I was able to fix this by a combination of renaming the method and passing a dummy variable. Changes were to the lines:
form.html.erb:
<% form_tag( poop_individual_shifts_path ) do %>
routes.rb:
map.poop_individual_shifts "poop_shifts", :controller => 'shifts', :action => "poop_individual", :method => "put", :id => 4
map.resources :shifts
There I pass it an ID of 4 every time, it doesn't matter, it's not actually doing anything with the shift object it goes and grabs, it's just ... I don't know, a hack, I guess.
shifts_controller.rb:
def poop_individual

embeddable component in views or how to call a different controller

Let's say you have a form that has its own controller. Is there any way to embed this form in different views (governed by other controllers)? As far as I understand partial templates carry only logic in the Ruby code that is inside the template. I am thinking more of a full-blown component where maybe you can call its controller.
The form is not driven that directly by the controllers. Yeah this is the price of all this magic.
To clarify a bit:
You type in your browser http://yourhost/posts
Your request (GET /posts) hits the router, then your router says that the /post urls belongs to the PostsController and the action is index
Then your controller executes the index method, do your business logic (loads the posts from the database, for example)
loads the view (views/posts/index...) and run it by 'substituting' all the instance variables and stuff defined in your controller (eg #posts = Post.all) that you have in it
then you see the view rendered with a list of posts (if in the view you have something similar to #posts.map{|p| p.title}.join(", ") )
yes I know it's not the best /posts view in the world but it's only to grasp the idea
The same goes for form, your form tag (for example form_for) gets an instance from the controller (let's say #post) and (in edit mode) gets filled with your Post attributes.
Then when you (edit something and) click the submit button it makes a request (by default a PUT to /posts) passing all the values in the form, then your controller gets the (POST) values of the requests (the ones you see in the server log) and makes his work (like saving the post's datas)
and because of this in a controller you can use the method
render :controller => :foo, :action => :bar
to render another controller action different from the default one
Hope this will be useful!
You can create a form in any view to call any controller. In a RESTful app, you can usually just pass an empty object (using the Posts/Commments example from makevoid)
<% form_for #new_comment do |f| %>
<%= f.text_area :text %>
<%= f.submit %>
<% end %>
This form should route to the create action on CommentsController. From there, you could use redirect_to :back in order to get back to the view that triggered this controller. This does have some validation issues I think though.
If you are non-RESTful, you can use the old form_for style:
<% form_for :comment, #new_comment, :url => { :controller => "comments", :action => "create" } do |f| %>
<%= f.text_area :text %>
<%= f.submit %>
<% end %>
For either of these examples, you need to have the #new_comment, which you would create in your PostsController:
def show
#post = Posts.find(params[:id])
#new_comment = #post.comments.build
end

Resources