This is another I'm-totally-new-to-Ruby-please-have-mercy situation.
So i'm trying to figure out how to make a database of all my buttons to save the click count each time they're clicked. I started a new rails to try it out and generated a model Buttonand a controller buttons index
route.rbs
Rails.application.routes.draw do
resources :buttons
root 'buttons#index'
end
migration
class CreateButtons < ActiveRecord::Migration[5.0]
def change
create_table :buttons do |t|
t.integer :clicks
t.timestamps
end
end
end
buttons_controller
class ButtonsController < ApplicationController
def index
#button = Button.find(1)
end
def doit
#button = Button.find(1)
#newcount = #button.clicks + 1
Button.find(1).update_attributes(:clicks => #newcount)
end
end
Now.. i need to trigger the doit method.. is it possible to trigger a non CRUD operation ?
i tried this but it doesn't seem to work
index.html.erb
<h1>Hello, This is button and my click are :</h1>
<h1><%= #button.clicks %></h1>
<%= link_to 'click me', method: :doit %>
I know there's something I'm not getting here...
Ruby have been doing so much magic that I can't do a simple ruby method.. it have been really hard for me getting the part were methods are taking place without calling them by name..
Specially when I trigger a delete method and the destroy method is triggered by that.. I really need to get used to this too-much-magic coding
Several things to improve, I think. Please get back to me if something is not working (I did not run the code)
Make your index action list all the buttons
Controller:
def index
#buttons = Button.all
end
View:
<h1>These are all my buttons</h1>
<% #buttons.each do |button| %>
<%= link_to("Button #{button.id}", button_votes_path(button), method: :post) %>
<% end %>
It's common to have index show a list of resources.
Only create the routes you need, make increment a separate action
I'd chose to call it "vote". You could also call it "clicks" or "presses" or whatever.
resources :buttons, only: [:index] do
resources :votes, only: [:create]
end
Add the votes controller
class VotesController < ApplicationController
def create
button = Button.find(params[:id])
button.clicks += 1
button.save
redirect_to buttons_path
end
end
No error handling here. So this is just to get you started.
For the next steps I suggest you follow a tutorial or start with simpler stuff.
Related
I am creating a small college project in Ruby on Rails, and I came across a problem: I have a table named Person and another called Tools.
People have many tools and each tool and possessed by a person.
I need to add a feature that allows the loan of tools between people of the system. For this, I created an attribute called 'loan' in the Tools table, which has a value of 0 means that the tool not this borrowed and if it is 1, that this borrowed. In view show the tools, I created a button with the function to borrow the tool. My problem is how do to make this button change the attribute 'loan' from the Tools table from 0 to 1 and then reverse it. Someone would have a solution or a better suggestion?
I would create 2 routes name "barrow" and "retrieve" like this:
#config/routes.rb
get '/tool/:id/barrow' => 'tools#barrow', as: :barrow
get '/tool/:id/retrieve' => 'tools#retrieve', as: :retrieve
Now in your view you can do something like
# tool.index.html.erb
...
<% if tool.loan %>
<%= link_to retrieve_path(tool), 'Retrieve', class: 'btn ...' %>
<% else %>
<%= link_to barrow_path(tool), 'Barrow', class: 'btn ...' %>
<% end %>
...
now you have to create the controller action you have to create the retrieve and barrow methods
#app/controllers/tool_controller.rb
class UserController < ApplicationController
...
def retrieve
#tool = Tool.find_by(params[:tool])
#tool.update_attributes(:loan, 0)
end
def barrow
#tool = Tool.find_by(params[:tool])
#tool.update_attributes(:loan, 1)
end
...
end
I hope that this help you
I am a beginer and I just created a welcomes controller and model welcome with title:string and name:text, and when I run to check does it work or not I get this error which I don't understand since it is very basic code! I should get at least a blank page not error!
views/welcome/index.html.erb
<h1>Welcomes#index</h1>
<%= #welcomes.each do |f| %>
<%= f.title %>
<%= f.name %>
<% end %>
controllers/welcomes/
class WelcomesController < ApplicationController
def index
#welcomes=Welcome.All
end
def show
end
def create
end
end
the error I get :
NoMethodError in WelcomesController#index
undefined method 'All' for #<Class:0x007f8bb2af5060>
class WelcomesController < ApplicationController
def index
#welcomes=Welcome.All
end
Within index action of Welcomes Controller modify:
#welcomes = Welcomes.All to
#welcomes = Welcome.all
The model name is Welcome and you are using plural of it within index action which generated the error.
class ProfileController < ApplicationController
def show
#user = current_user
#first_name = #user.first_name
#last_name = #user.last_name
end
def settings
end
def pics
#photos = current_user.photos.all
end
end
in the view of _pics.html.erb, I have
<% #photos.each do |p| %>
<%= image_tag p.image(:medium) %>
<% end %>
If I change it to current_user.photos.each do |p|, it works, which is weird. I don't get an error from this code on my other computer.
In a comment you said, that you render the pics partial from your show view. Since the show view is rendered by the show action and the show action does not set the #photos variable, you can't use that variable. So to fix your problem, you'd need to set the variable in the show action.
You seem to think that rendering the pics partial will invoke the pics action, but that's not the case. An action will only be invoked if an URL is accessed that's mapped to that using the routing system. Rendering partials does not invoke any actions.
Also it should just be #photos = current_user.photos without the all.
I have a edit form which I have a radio_button that I would like to pass to a controller action and then use it to do a calculation. In the view I have:
<div class="field">
<%= radio_button_tag(:rating_select, "Up") %>
<%= label_tag(:rating_select, "Good.") %>
<%= radio_button_tag(:rating_select, "Down")%>
<%= label_tag(:rating_select, "Bad.")%>
</div>
In the controller I have:
def rating
#post = Post.find(params[:id])
.....
end
def update
#post = Post.find(params[:id])
##rating_select = params[:rating_select]
if #post.rating_select == "Up"
#post.score += 5
elsif #post.rating_select == "Down"
#post.score -= 5
end
......
end
Currently it is ignoring the if statement so the parameter isn't getting set properly. Ideally I would like to just use a temp variable from the view to use in the if statement to decide if I need to add or subtract in the update. But I also have a rating_select field in post if I need to use it also. Thanks.
UPDATE:
Thanks. That makes sense, I changed it to below but it still isn't incrementing or decrementing the score based on the radio box. So it seems it isn't getting the rating_select?:
def update
#post = Post.find(params[:id])
if params[:rating_select]=="Up"
#post.score += 5
elsif params[:rating_select]=="Down"
#post.score -= 5
end
respond_to do |format|
....
UPDATE2:
Finally figured it out, used another model Ratings to store association. I used the before_save in the Post model and it allowed me to do the calculation and save. What a headache.
before_save :set_rating
def set_rating
if self.rating.rating_select=="Up"
rating.score += 5
elsif self.rating.rating_select=="Down"
rating.score -= 5
end
end
Well, first off, in the code you're showing the post loaded in your update action is not receiving the params from your view.
Your code for an update action should typically look like this:
def update
#post = Post.find(params[:id])
if #post.update_attributes(params[:post])
... do stuff ...
else
render :edit, :alert => 'Unable to update post.'
end
end
Second, since you're using form_tag helper and not form_for, then you're not getting the params all setup for your model (ie. nested under params[:post]). So, in this case, your rating_select option is just a value by itself, which you can test for like this:
if params[:rating_select]=="Up"
...
else
...
end
The big thing to understand from your code is #post doesn't know anything about params[:rating_select], even if you used #post.update_attributes(params[:post]), because radio_button_tag as you have it set up is not building a hash of post attributes, it's just a standalone field.
I hope that makes sense, if you don't understand please leave comments and I'll try to explain more.
I'm creating CSV-upload functionality for a site of mine.
I'm looking to upload a file, parse it, and then dispose of it.
I know I can upload and save a file using Paperclip, but that seems a bit like overkill.
All I need to do is parse the uploaded file and never save it.
How would I go about doing this in Rails 3?
Note: I'd prefer to do the uploading manually without using an external gem so I can learn how to process works, but any suggestions are welcome.
Thanks!
Use the file_field helper in your form, then in your controller you can use File.Write and File.read to save the file.
E.g. View
<%= form_for #ticket do |f| %>
<%= f.file_field :uploaded_file %>
<% end %>
Controller
def upload
uploaded = params[:ticket][:uploaded_file]
File.open(<insert_filename_here>, 'w') do |file|
file.write(uploaded.read)
end
end
Edit: Just saw #klochner's comment, that link says pretty much what I have said so follow that: RubyOnRails Guides: Uploading Files.
Paste this in your model
def parse_file
File.open(uploaded/file/path, 'w') do |f| # Feed path that user gives in some way
## Parse here
end
end
this in view
<%=form_for #page, :multipart => true do |f|%>
<ul><li><%= f.label :file%></li>
<li><%= f.file_field :uploaded_file%></li></ul>
<%end%>
Let me know if this works. If it fails figure out a way to feed path of uploaded_file in parse_file method (the definite way which will work is storing file location in db and picking up from there, but it is not the right way to do this thing). Otherwise, I guess it should work.
Complete Example
Take, for example, uploading an import file containing contacts. You don't need to store this import file, just process it and discard it.
Routes
routes.rb
resources :contacts do
collection do
get 'import/new', to: :new_import # import_new_contacts_path
post :import, on: :collection # import_contacts_path
end
end
Form
views/contacts/new_import.html.erb
<%= form_for #contacts, url: import_contacts_path, html: { multipart: true } do |f| %>
<%= f.file_field :import_file %>
<% end %>
Controller
controllers/contacts_controller.rb
def new_import
end
def import
begin
Contact.import( params[:contacts][:import_file] )
flash[:success] = "<strong>Contacts Imported!</strong>"
redirect_to contacts_path
rescue => exception
flash[:error] = "There was a problem importing that contacts file.<br>
<strong>#{exception.message}</strong><br>"
redirect_to import_new_contacts_path
end
end
Contact Model
models/contact.rb
def import import_file
File.foreach( import_file.path ).with_index do |line, index|
# Process each line.
# For any errors just raise an error with a message like this:
# raise "There is a duplicate in row #{index + 1}."
# And your controller will redirect the user and show a flash message.
end
end